| import gradio as gr |
| import json |
| from clinical_ner import ClinicalNERProcessor |
|
|
| |
| ner_processor = ClinicalNERProcessor(use_pos=True, use_anatomy=True) |
|
|
| |
| EXAMPLE_TEXT = "Patient presents with pain in the left ventricle and elevated cardiac enzymes. The heart shows signs of inflammation." |
|
|
| def format_entities(entities): |
| """Format entities for display""" |
| if not entities: |
| return "No entities found." |
| |
| result = [] |
| for i, entity in enumerate(entities, 1): |
| result.append(f"{i}. **{entity['word']}** - Type: {entity['entity_group']} (Score: {entity['score']:.4f})") |
| return "\n".join(result) |
|
|
| def format_pos_tags(pos_tags): |
| """Format POS tags for display""" |
| if not pos_tags: |
| return "No POS tags found." |
| |
| result = [] |
| for i, tag in enumerate(pos_tags, 1): |
| result.append(f"{i}. **{tag['token']}** - POS: {tag['pos']}, Tag: {tag['tag']}, Lemma: {tag['lemma']}") |
| return "\n".join(result) |
|
|
| def clinical_ner_basic(text): |
| """Clinical NER only""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| entities = ner_processor.basic_ner(text) |
| return format_entities(entities) |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def clinical_ner_prolog(text): |
| """Clinical NER as Prolog facts""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| prolog_facts = ner_processor.prolog_ner(text) |
| return prolog_facts if prolog_facts else "No entities found." |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def anatomy_ner_basic(text): |
| """Anatomy NER only""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| entities = ner_processor.anatomy_ner(text) |
| return format_entities(entities) |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def anatomy_ner_prolog(text): |
| """Anatomy NER as Prolog facts""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| prolog_facts = ner_processor.prolog_anatomy(text) |
| return prolog_facts if prolog_facts else "No entities found." |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def pos_tagging_basic(text): |
| """POS tagging only""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| pos_tags = ner_processor.pos_tagging(text) |
| return format_pos_tags(pos_tags) |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def pos_tagging_prolog(text): |
| """POS tagging as Prolog facts""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| prolog_facts = ner_processor.prolog_pos(text) |
| return prolog_facts if prolog_facts else "No POS tags found." |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| def combined_analysis(text): |
| """Combined analysis""" |
| if not text.strip(): |
| return "Please enter some text.", "Please enter some text.", "Please enter some text." |
| try: |
| result = ner_processor.combined_analysis(text) |
| clinical = format_entities(result['clinical_entities']) |
| anatomy = format_entities(result['anatomy_entities']) |
| pos = format_pos_tags(result['pos_tags']) |
| return clinical, anatomy, pos |
| except Exception as e: |
| error_msg = f"Error: {str(e)}" |
| return error_msg, error_msg, error_msg |
|
|
| def combined_prolog(text): |
| """Combined analysis as Prolog facts""" |
| if not text.strip(): |
| return "Please enter some text." |
| try: |
| prolog_facts = ner_processor.prolog_combined(text) |
| return prolog_facts if prolog_facts else "No results found." |
| except Exception as e: |
| return f"Error: {str(e)}" |
|
|
| |
| with gr.Blocks(title="Clinical NER & Anatomy Detection", theme=gr.themes.Soft()) as demo: |
| gr.Markdown( |
| """ |
| # Clinical NER, Anatomy Detection, and POS Tagging |
| |
| This application provides Named Entity Recognition (NER) for clinical text, |
| anatomy detection, and Part-of-Speech (POS) tagging using state-of-the-art models: |
| - **Clinical NER**: Bio_ClinicalBERT |
| - **Anatomy NER**: OpenMed AnatomyDetect |
| - **POS Tagging**: spaCy en_core_web_sm |
| """ |
| ) |
| |
| with gr.Tabs(): |
| |
| with gr.Tab("Clinical NER"): |
| with gr.Row(): |
| with gr.Column(): |
| clinical_input = gr.Textbox( |
| label="Enter Clinical Text", |
| placeholder="Enter medical text here...", |
| lines=5, |
| value=EXAMPLE_TEXT |
| ) |
| clinical_format = gr.Radio( |
| choices=["Basic", "Prolog"], |
| value="Basic", |
| label="Output Format" |
| ) |
| clinical_btn = gr.Button("Extract Clinical Entities", variant="primary") |
| |
| with gr.Column(): |
| clinical_output = gr.Textbox( |
| label="Clinical Entities", |
| lines=15, |
| show_copy_button=True |
| ) |
| |
| def clinical_ner_process(text, format_type): |
| if format_type == "Basic": |
| return clinical_ner_basic(text) |
| else: |
| return clinical_ner_prolog(text) |
| |
| clinical_btn.click( |
| fn=clinical_ner_process, |
| inputs=[clinical_input, clinical_format], |
| outputs=clinical_output |
| ) |
| |
| |
| with gr.Tab("Anatomy Detection"): |
| with gr.Row(): |
| with gr.Column(): |
| anatomy_input = gr.Textbox( |
| label="Enter Clinical Text", |
| placeholder="Enter medical text here...", |
| lines=5, |
| value=EXAMPLE_TEXT |
| ) |
| anatomy_format = gr.Radio( |
| choices=["Basic", "Prolog"], |
| value="Basic", |
| label="Output Format" |
| ) |
| anatomy_btn = gr.Button("Detect Anatomy", variant="primary") |
| |
| with gr.Column(): |
| anatomy_output = gr.Textbox( |
| label="Anatomy Entities", |
| lines=15, |
| show_copy_button=True |
| ) |
| |
| def anatomy_ner_process(text, format_type): |
| if format_type == "Basic": |
| return anatomy_ner_basic(text) |
| else: |
| return anatomy_ner_prolog(text) |
| |
| anatomy_btn.click( |
| fn=anatomy_ner_process, |
| inputs=[anatomy_input, anatomy_format], |
| outputs=anatomy_output |
| ) |
| |
| |
| with gr.Tab("POS Tagging"): |
| with gr.Row(): |
| with gr.Column(): |
| pos_input = gr.Textbox( |
| label="Enter Text", |
| placeholder="Enter text here...", |
| lines=5, |
| value=EXAMPLE_TEXT |
| ) |
| pos_format = gr.Radio( |
| choices=["Basic", "Prolog"], |
| value="Basic", |
| label="Output Format" |
| ) |
| pos_btn = gr.Button("Tag POS", variant="primary") |
| |
| with gr.Column(): |
| pos_output = gr.Textbox( |
| label="POS Tags", |
| lines=15, |
| show_copy_button=True |
| ) |
| |
| def pos_process(text, format_type): |
| if format_type == "Basic": |
| return pos_tagging_basic(text) |
| else: |
| return pos_tagging_prolog(text) |
| |
| pos_btn.click( |
| fn=pos_process, |
| inputs=[pos_input, pos_format], |
| outputs=pos_output |
| ) |
| |
| |
| with gr.Tab("Combined Analysis"): |
| with gr.Row(): |
| with gr.Column(): |
| combined_input = gr.Textbox( |
| label="Enter Clinical Text", |
| placeholder="Enter medical text here...", |
| lines=5, |
| value=EXAMPLE_TEXT |
| ) |
| combined_format = gr.Radio( |
| choices=["Basic (Separated)", "Prolog (Combined)"], |
| value="Basic (Separated)", |
| label="Output Format" |
| ) |
| combined_btn = gr.Button("Analyze All", variant="primary") |
| |
| with gr.Row(): |
| with gr.Column(): |
| combined_clinical = gr.Textbox( |
| label="Clinical Entities", |
| lines=10, |
| show_copy_button=True, |
| visible=True |
| ) |
| |
| with gr.Column(): |
| combined_anatomy = gr.Textbox( |
| label="Anatomy Entities", |
| lines=10, |
| show_copy_button=True, |
| visible=True |
| ) |
| |
| with gr.Column(): |
| combined_pos = gr.Textbox( |
| label="POS Tags", |
| lines=10, |
| show_copy_button=True, |
| visible=True |
| ) |
| |
| combined_prolog_output = gr.Textbox( |
| label="Combined Prolog Output", |
| lines=20, |
| show_copy_button=True, |
| visible=False |
| ) |
| |
| def combined_process(text, format_type): |
| if format_type == "Basic (Separated)": |
| clinical, anatomy, pos = combined_analysis(text) |
| return { |
| combined_clinical: gr.update(value=clinical, visible=True), |
| combined_anatomy: gr.update(value=anatomy, visible=True), |
| combined_pos: gr.update(value=pos, visible=True), |
| combined_prolog_output: gr.update(visible=False) |
| } |
| else: |
| prolog = combined_prolog(text) |
| return { |
| combined_clinical: gr.update(visible=False), |
| combined_anatomy: gr.update(visible=False), |
| combined_pos: gr.update(visible=False), |
| combined_prolog_output: gr.update(value=prolog, visible=True) |
| } |
| |
| combined_btn.click( |
| fn=combined_process, |
| inputs=[combined_input, combined_format], |
| outputs=[combined_clinical, combined_anatomy, combined_pos, combined_prolog_output] |
| ) |
| |
| gr.Markdown( |
| """ |
| --- |
| ### Models Used: |
| - Clinical NER: `samrawal/bert-base-uncased_clinical-ner` |
| - Anatomy Detection: `OpenMed/OpenMed-NER-AnatomyDetect-BioPatient-108M` |
| - POS Tagging: spaCy `en_core_web_sm` |
| """ |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |