Spaces:
Running
Running
import json | |
from typing import Dict, Union, List | |
from gliner import GLiNER | |
import gradio as gr | |
import os | |
# Load available models | |
MODELS = { | |
"GLiNER Medium v2.1": "urchade/gliner_medium-v2.1", | |
"NuNER Zero": "numind/NuZero_token", | |
"GLiNER Multi PII": "urchade/gliner_multi_pii-v1" | |
} | |
# Example datasets with descriptions | |
EXAMPLE_SETS = { | |
"General NER": "examples.json", | |
"NuNER Zero": "examples-nuner.json", | |
"PII Detection": "examples-pii.json" | |
} | |
# Initialize models (will be loaded on demand) | |
loaded_models = {} | |
# Current examples | |
current_examples = [] | |
def load_example_set(example_set_name): | |
"""Load a set of examples from the specified file""" | |
try: | |
file_path = EXAMPLE_SETS[example_set_name] | |
with open(file_path, "r", encoding="utf-8") as f: | |
examples = json.load(f) | |
return examples | |
except (KeyError, FileNotFoundError, json.JSONDecodeError) as e: | |
print(f"Error loading example set {example_set_name}: {e}") | |
return [] | |
# Load default example set | |
current_examples = load_example_set("General NER") | |
def get_model(model_name): | |
"""Load model if not already loaded""" | |
if model_name not in loaded_models: | |
model_path = MODELS[model_name] | |
loaded_models[model_name] = GLiNER.from_pretrained(model_path) | |
return loaded_models[model_name] | |
def merge_entities(entities): | |
"""Merge adjacent entities of the same type""" | |
if not entities: | |
return [] | |
merged = [] | |
current = entities[0] | |
for next_entity in entities[1:]: | |
if (next_entity['entity'] == current['entity'] and | |
(next_entity['start'] == current['end'] + 1 or next_entity['start'] == current['end'])): | |
current['word'] += ' ' + next_entity['word'] | |
current['end'] = next_entity['end'] | |
else: | |
merged.append(current) | |
current = next_entity | |
merged.append(current) | |
return merged | |
def ner( | |
text: str, | |
labels: str, | |
model_name: str, | |
threshold: float, | |
nested_ner: bool, | |
merge_entities_toggle: bool | |
) -> Dict[str, Union[str, List]]: | |
"""Run named entity recognition with selected model and parameters""" | |
# Get the selected model | |
model = get_model(model_name) | |
# Split labels | |
label_list = [label.strip() for label in labels.split(",")] | |
# Predict entities | |
entities = [ | |
{ | |
"entity": entity["label"], | |
"word": entity["text"], | |
"start": entity["start"], | |
"end": entity["end"], | |
"score": entity.get("score", 0), | |
} | |
for entity in model.predict_entities( | |
text, label_list, flat_ner=not nested_ner, threshold=threshold | |
) | |
] | |
# Merge entities if enabled | |
if merge_entities_toggle: | |
entities = merge_entities(entities) | |
# Return results | |
return { | |
"text": text, | |
"entities": entities, | |
} | |
def load_example(example_idx): | |
"""Load a specific example by index from the current example set""" | |
if not current_examples or example_idx >= len(current_examples): | |
return "", "", 0.3, False, False | |
example = current_examples[example_idx] | |
return example[0], example[1], example[2], example[3], False | |
def switch_example_set(example_set_name): | |
"""Switch to a different example set and update the interface""" | |
global current_examples | |
current_examples = load_example_set(example_set_name) | |
# Return the first example from the new set | |
if current_examples: | |
example = current_examples[0] | |
# Return example text, labels, threshold, nested_ner, merge status, example names for dropdown | |
example_names = [f"Example {i+1}" for i in range(len(current_examples))] | |
return example[0], example[1], example[2], example[3], False, gr.Dropdown.update(choices=example_names, value="Example 1") | |
else: | |
return "", "", 0.3, False, False, gr.Dropdown.update(choices=[], value=None) | |
with gr.Blocks(title="Unified NER Interface") as demo: | |
gr.Markdown( | |
""" | |
# Unified Zero-shot Named Entity Recognition Interface | |
This interface allows you to compare different zero-shot Named Entity Recognition models. | |
## Models Available: | |
- **GLiNER Medium v2.1**: The original GLiNER medium model | |
- **NuNER Zero**: A specialized token-based NER model | |
- **GLiNER Multi PII**: Fine-tuned for detecting personally identifiable information across multiple languages | |
## Features: | |
- Select different models | |
- Switch between example sets for different use cases | |
- Toggle nested entity recognition | |
- Toggle entity merging (combining adjacent entities of the same type) | |
- Select from various examples within each set | |
""" | |
) | |
with gr.Row(): | |
model_dropdown = gr.Dropdown( | |
choices=list(MODELS.keys()), | |
value=list(MODELS.keys())[0], | |
label="Model", | |
info="Select the NER model to use" | |
) | |
example_set_dropdown = gr.Dropdown( | |
choices=list(EXAMPLE_SETS.keys()), | |
value="General NER", | |
label="Example Set", | |
info="Select a set of example texts" | |
) | |
with gr.Row(): | |
example_dropdown = gr.Dropdown( | |
choices=[f"Example {i+1}" for i in range(len(current_examples))], | |
value="Example 1", | |
label="Example", | |
info="Select a specific example text" | |
) | |
input_text = gr.Textbox( | |
value=current_examples[0][0] if current_examples else "", | |
label="Text input", | |
placeholder="Enter your text here", | |
lines=5 | |
) | |
with gr.Row(): | |
labels = gr.Textbox( | |
value=current_examples[0][1] if current_examples else "", | |
label="Entity Labels", | |
placeholder="Enter your labels here (comma separated)", | |
scale=2, | |
) | |
threshold = gr.Slider( | |
0, | |
1, | |
value=current_examples[0][2] if current_examples else 0.3, | |
step=0.01, | |
label="Confidence Threshold", | |
info="Lower the threshold to increase how many entities get predicted.", | |
scale=1, | |
) | |
with gr.Row(): | |
nested_ner = gr.Checkbox( | |
value=current_examples[0][3] if current_examples else False, | |
label="Nested NER", | |
info="Allow entities to be contained within other entities", | |
) | |
merge_entities_toggle = gr.Checkbox( | |
value=False, | |
label="Merge Adjacent Entities", | |
info="Combine adjacent entities of the same type into a single entity", | |
) | |
output = gr.HighlightedText(label="Predicted Entities") | |
submit_btn = gr.Button("Submit") | |
# Handling example set selection | |
example_set_dropdown.change( | |
fn=switch_example_set, | |
inputs=[example_set_dropdown], | |
outputs=[input_text, labels, threshold, nested_ner, merge_entities_toggle, example_dropdown] | |
) | |
# Handling example selection within a set | |
example_dropdown.change( | |
fn=lambda idx: load_example(int(idx.split()[1]) - 1), | |
inputs=[example_dropdown], | |
outputs=[input_text, labels, threshold, nested_ner, merge_entities_toggle] | |
) | |
# Add a model recommendation for the example set | |
def recommend_model(example_set_name): | |
"""Recommend appropriate model based on example set""" | |
if example_set_name == "PII Detection": | |
return gr.Dropdown.update(value="GLiNER Multi PII") | |
elif example_set_name == "NuNER Zero": | |
return gr.Dropdown.update(value="NuNER Zero") | |
else: | |
return gr.Dropdown.update(value="GLiNER Medium v2.1") | |
# Auto-suggest model when changing example set | |
example_set_dropdown.change( | |
fn=recommend_model, | |
inputs=[example_set_dropdown], | |
outputs=[model_dropdown] | |
) | |
# Submitting | |
submit_btn.click( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
input_text.submit( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
# Other interactions | |
model_dropdown.change( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
threshold.release( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
nested_ner.change( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
merge_entities_toggle.change( | |
fn=ner, | |
inputs=[input_text, labels, model_dropdown, threshold, nested_ner, merge_entities_toggle], | |
outputs=output | |
) | |
if __name__ == "__main__": | |
demo.queue() | |
demo.launch(debug=True) |