# LabelConcept

[`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) is a classification concept type in ContextGem that categorizes documents or content using predefined labels, supporting both single-label and multi-label classification approaches.

## 🏷️ Overview

[`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) is used when you need to classify content into predefined categories, including:

* **Document classification**: contract types, document categories, legal classifications
* **Content categorization**: topics, themes, subjects, areas of focus
* **Quality assessment**: compliance levels, risk categories, priority levels
* **Multi-faceted tagging**: multiple applicable labels for comprehensive classification

This concept type supports two classification modes:

* **Multi-class**: Selects exactly one label from the predefined set (mutually exclusive labels) - used for classifying the content into a single type or category. The model is to select the closest label even if none fits perfectly: a decision model always does, while an LLM can still return no item, so check that `extracted_items` is not empty.
* **Multi-label**: Selects zero, one, or multiple labels from the predefined set (non-exclusive labels) - used when multiple topics or attributes can apply simultaneously. Returns only applicable labels, or no labels if none apply (the `extracted_items` list is then empty).

#### IMPORTANT
**For multi-class classification**: Since multi-class classification selects exactly one label, you should consider including a general “other” label (such as “N/A”, “misc”, “unspecified”, etc.) to handle cases where none of the specific labels apply, unless your labels are broad enough to cover all cases, or you know that the classified content always falls under one of the predefined labels without edge cases. This ensures appropriate classification even when the content doesn’t clearly fit into any of the predefined specific categories.

## 💻 Usage Example

Here’s a basic example of how to use [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) for document type classification:

```python
# ContextGem: Contract Type Classification using LabelConcept

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document object from legal document text
legal_doc_text = """
NON-DISCLOSURE AGREEMENT

This Non-Disclosure Agreement ("Agreement") is entered into as of January 15, 2025, by and between TechCorp Inc., a Delaware corporation ("Disclosing Party"), and DataSystems LLC, a California limited liability company ("Receiving Party").

WHEREAS, Disclosing Party possesses certain confidential information relating to its proprietary technology and business operations;

NOW, THEREFORE, in consideration of the mutual covenants contained herein, the parties agree as follows:

1. CONFIDENTIAL INFORMATION
The term "Confidential Information" shall mean any and all non-public information...

2. OBLIGATIONS OF RECEIVING PARTY
Receiving Party agrees to hold all Confidential Information in strict confidence...
"""

doc = Document(raw_text=legal_doc_text)

# Define a LabelConcept for contract type classification
contract_type_concept = LabelConcept(
    name="Contract Type",
    description="Classify the type of contract",
    labels=["NDA", "Consultancy Agreement", "Privacy Policy", "Other"],
    classification_type="multi_class",  # only one label can be selected (mutually exclusive labels)
    singular_occurrence=True,  # expect only one classification result
)

# Attach the concept to the document
doc.add_concepts([contract_type_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
contract_type_concept = llm.extract_concepts_from_document(doc)[0]

# Check if any labels were extracted
if contract_type_concept.extracted_items:
    # Get the classified document type
    classified_type = contract_type_concept.extracted_items[0].value
    print(f"Document classified as: {classified_type}")  # Output: ['NDA']
else:
    print("No applicable labels found for this document")
```

## ⚙️ Parameters

When creating a [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept), you can specify the following parameters:

| Parameter                 | Type           | Default Value   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|---------------------------|----------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name`                    | `str`          | (Required)      | A unique name identifier for the concept                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `description`             | `str`          | (Required)      | A clear description of what the concept represents and how classification should be performed                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `labels`                  | `list[str]`    | (Required)      | List of predefined labels for classification. Must contain at least 2 unique labels                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `classification_type`     | `str`          | `"multi_class"` | Classification mode. Available values: `"multi_class"` (select exactly one label), `"multi_label"` (select zero, one, or several labels).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `model_role`              | `str | None`   | `None`          | The role label of the model that extracts the concept when a model group is used: the concept is routed to the model in the group with the same `role`. With the default `None`, the concept is routed to the model without a role. Ignored when a single model is used, as it extracts every concept it is given. For more details, see [🏷️ Model Roles](https://contextgem.shcherbak.ai/optimizations/optimization_choosing_llm/index.html.md#model-roles-label).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `modality`                | `str`          | `"text"`        | The document content the concept is extracted from. Available values: `"text"`, `"image"`, `"multimodal"` (text and/or images, whichever the document has). `"image"` and `"multimodal"` are supported for document-level concepts only, and require an LLM that supports vision when the document has images. A concept with `"image"` cannot have `add_references=True`. A decision model extracts from text only, and rejects `"image"` and `"multimodal"` with `ValueError` before any request is sent (see [✅ Supported Aspects and Concepts](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-supported-label)). For more details, see [🖼️ Concept Modality](https://contextgem.shcherbak.ai/optimizations/optimization_choosing_llm/index.html.md#concept-modality-label).                                                                                                                                                                                                      |
| `add_justifications`      | `bool`         | `False`         | Whether to include justifications for extracted items. Justifications provide explanations of why specific labels were selected and the reasoning behind the classification decision. A decision model provides no justifications, and rejects `True` with `ValueError` before any request is sent (see [✅ Supported Aspects and Concepts](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-supported-label)).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `justification_depth`     | `str`          | `"brief"`       | Justification detail level. Available values: `"brief"`, `"balanced"`, `"comprehensive"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `justification_max_sents` | `int`          | `2`             | Maximum sentences in a justification.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `add_references`          | `bool`         | `False`         | Whether to include source references for extracted items. References indicate the specific locations in the document that informed the classification decision. A decision model provides no references for concepts, and rejects `True` with `ValueError` before any request is sent (see [✅ Supported Aspects and Concepts](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-supported-label)).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `reference_depth`         | `str`          | `"paragraphs"`  | Source reference granularity. Available values: `"paragraphs"`, `"sentences"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `decision_threshold`      | `float | None` | `None`          | Relevant when the concept is extracted by a decision model ([`DocumentDecisionModel`](https://contextgem.shcherbak.ai/api/decision_models/index.html.md#contextgem.public.decision_models.DocumentDecisionModel)): the lowest probability (above 0, up to 1) with which a label is selected. Can be set for `classification_type="multi_label"` only: with `"multi_class"`, the most probable label is always selected, and setting the threshold raises a validation error. With the default `None`, the `decision_threshold` of the decision model applies. Ignored when the concept is extracted by an LLM. See [🎚️ Decision Threshold](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-threshold-label).                                                                                                                                                                                                                                                       |
| `singular_occurrence`     | `bool`         | `False`         | Whether this concept has at most one extracted item. If `True`, at most one item is extracted, and none if there is nothing to extract: an LLM that returns more than one is asked again, as for any other invalid data. This is particularly useful for global document classifications where only one classification result is expected. With a decision model ([`DocumentDecisionModel`](https://contextgem.shcherbak.ai/api/decision_models/index.html.md#contextgem.public.decision_models.DocumentDecisionModel)), a concept gets at most one item with or without this parameter, unless the text is sent in parts, i.e. `max_paragraphs_to_analyze_per_call` is passed to the extraction method: a decision model then returns an item for each part, and rejects a concept with `singular_occurrence=True` with `ValueError` before any request is sent. See [sending a long text in parts](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-parts-label). |
| `custom_data`             | `dict`         | `{}`            | Optional. Dictionary for storing any additional data that you want to associate with the concept. This data must be JSON-serializable. This data is not used for extraction but can be useful for custom processing or downstream tasks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

## 🚀 Advanced Usage

### 🏷️ Multi-Class vs Multi-Label Classification

Choose the classification type based on your use case:

- **Multi-class** (`classification_type="multi_class"`) is ideal for document types, priority levels, and status categories. Example: a document is classified as one of “NDA”, “Consultancy Agreement”, “Privacy Policy”, or “Other” if none of them applies.
- **Multi-label** (`classification_type="multi_label"`) is ideal for content topics, applicable regulations, and feature tags. Example: a document can cover several of the topics “Finance”, “Legal”, “Technology”, or none of them.

Here’s an example demonstrating multi-label classification for content topic identification:

```python
# ContextGem: Multi-Label Classification with LabelConcept

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document object with business document text covering multiple topics
business_doc_text = """
QUARTERLY BUSINESS REVIEW - Q4 2024

FINANCIAL PERFORMANCE
Revenue for Q4 2024 reached $2.8 million, exceeding our target by 12%. The finance team has prepared detailed budget projections for 2025, with anticipated growth of 18% across all divisions.

TECHNOLOGY INITIATIVES
Our development team has successfully implemented the new cloud infrastructure, reducing operational costs by 25%. The IT department is now focusing on cybersecurity enhancements and data analytics platform upgrades.

HUMAN RESOURCES UPDATE
We welcomed 15 new employees this quarter, bringing our total headcount to 145. The HR team has launched a comprehensive employee wellness program and updated our remote work policies.

LEGAL AND COMPLIANCE
All regulatory compliance requirements have been met for Q4. The legal department has reviewed and updated our data privacy policies in accordance with recent legislation changes.

MARKETING STRATEGY
The marketing team launched three successful campaigns this quarter, resulting in a 40% increase in lead generation. Our digital marketing efforts have expanded to include LinkedIn advertising and content marketing.
"""

doc = Document(raw_text=business_doc_text)

# Define a LabelConcept for topic classification allowing multiple topics
content_topics_concept = LabelConcept(
    name="Document Topics",
    description="Identify all relevant business topics covered in this document",
    labels=[
        "Finance",
        "Technology",
        "HR",
        "Legal",
        "Marketing",
        "Operations",
        "Sales",
        "Strategy",
    ],
    classification_type="multi_label",  # multiple labels can be selected (non-exclusive labels)
)


# Attach the concept to the document
doc.add_concepts([content_topics_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
content_topics_concept = llm.extract_concepts_from_document(doc)[0]

# Check if any labels were extracted
if content_topics_concept.extracted_items:
    # Get all identified topics
    identified_topics = content_topics_concept.extracted_items[0].value
    print(f"Document covers the following topics: {', '.join(identified_topics)}")
    # Expected output might include: Finance, Technology, HR, Legal, Marketing
else:
    print("No applicable topic labels found for this document")
```

### 🔍 References and Justifications for Classification

You can configure a [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) to include justifications and references to understand classification decisions. This is particularly valuable when dealing with complex documents that might contain elements of multiple document types:

```python
# ContextGem: LabelConcept with References and Justifications

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document with content that might be challenging to classify
mixed_content_text = """
QUARTERLY BUSINESS REVIEW AND POLICY UPDATES
GlobalTech Solutions Inc. - February 2025

EMPLOYMENT AGREEMENT AND CONFIDENTIALITY PROVISIONS

This Employment Agreement ("Agreement") is entered into between GlobalTech Solutions Inc. ("Company") and Sarah Johnson ("Employee") as of February 1, 2025.

EMPLOYMENT TERMS
Employee shall serve as Senior Software Engineer with responsibilities including software development, code review, and technical leadership. The position is full-time with an annual salary of $125,000.

CONFIDENTIALITY OBLIGATIONS
Employee acknowledges that during employment, they may have access to confidential information including proprietary algorithms, customer data, and business strategies. Employee agrees to maintain strict confidentiality of such information both during and after employment.

NON-COMPETE PROVISIONS
For a period of 12 months following termination, Employee agrees not to engage in any business activities that directly compete with Company's core services within the same geographic market.

INTELLECTUAL PROPERTY
All work products, inventions, and discoveries made during employment shall be the exclusive property of the Company.

ADDITIONAL INFORMATION:

FINANCIAL PERFORMANCE SUMMARY
Q4 2024 revenue exceeded projections by 12%, reaching $3.2M. Cost optimization initiatives reduced operational expenses by 8%. The board approved a $500K investment in new data analytics infrastructure for 2025.

PRODUCT LAUNCH TIMELINE
The AI-powered customer analytics platform will launch Q2 2025. Marketing budget allocated: $200K for digital campaigns. Expected customer acquisition target: 150 new enterprise clients in the first quarter post-launch.
"""

doc = Document(raw_text=mixed_content_text)

# Define a LabelConcept with justifications and references enabled
document_classification_concept = LabelConcept(
    name="Document Classification with Evidence",
    description="Classify this document type and provide reasoning for the classification",
    labels=[
        "Employment Contract",
        "NDA",
        "Consulting Agreement",
        "Service Agreement",
        "Partnership Agreement",
        "Other",
    ],
    classification_type="multi_class",  # a single label is always returned
    add_justifications=True,  # enable justifications to understand classification reasoning
    justification_depth="comprehensive",  # provide detailed reasoning
    justification_max_sents=5,  # allow up to 5 sentences for justification
    add_references=True,  # include references to source text
    reference_depth="paragraphs",  # reference specific paragraphs that informed classification
    singular_occurrence=True,  # expect only one classification result
)

# Attach the concept to the document
doc.add_concepts([document_classification_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
document_classification_concept = llm.extract_concepts_from_document(doc)[0]

# Display the classification results with evidence
if document_classification_concept.extracted_items:
    item = document_classification_concept.extracted_items[0]

    print("=== DOCUMENT CLASSIFICATION RESULTS ===")
    print(f"Classification: {item.value[0]}")
    print("\nJustification:")
    print(f"{item.justification}")

    print("\nEvidence from document:")
    for i, paragraph in enumerate(item.reference_paragraphs, 1):
        print(f"{i}. {paragraph.raw_text}")

else:
    print("No classification could be determined - none of the predefined labels apply")

# This example demonstrates how justifications help explain why the LLM
# chose a specific classification and how references show which parts
# of the document informed that decision
```

### 🎯 Document Aspect Analysis

[`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) can be used to classify extracted [`Aspect`](https://contextgem.shcherbak.ai/api/aspects/index.html.md#contextgem.public.aspects.Aspect) instances, providing a powerful way to analyze and categorize specific information that has been extracted from documents. This approach allows you to first extract relevant content using aspects, then apply classification logic to those extracted items.

Here’s an example that demonstrates using [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) to classify the financial risk level of extracted financial obligations from legal contracts:

```python
# ContextGem: Aspect Analysis with LabelConcept

import os

from contextgem import Aspect, Document, DocumentLLM, LabelConcept


# Create a Document object from contract text
contract_text = """
SOFTWARE DEVELOPMENT AGREEMENT
...

SECTION 5. PAYMENT TERMS
Client shall pay Developer a total fee of $150,000 for the complete software development project, payable in three installments: $50,000 upon signing, $50,000 at milestone completion, and $50,000 upon final delivery.
...

SECTION 8. MAINTENANCE AND SUPPORT
Following project completion, Developer shall provide 12 months of maintenance and support services at a rate of $5,000 per month, totaling $60,000 annually.
...

SECTION 12. PENALTY CLAUSES
In the event of project delay beyond the agreed timeline, Developer shall pay liquidated damages of $2,000 per day of delay, with a maximum penalty cap of $50,000.
...

SECTION 15. INTELLECTUAL PROPERTY LICENSING
Client agrees to pay ongoing licensing fees of $10,000 annually for the use of Developer's proprietary frameworks and libraries integrated into the software solution.
...

SECTION 18. TERMINATION COSTS
Should Client terminate this agreement without cause, Client shall pay Developer 75% of all remaining unpaid fees, estimated at approximately $100,000 based on current project status.
...
"""

doc = Document(raw_text=contract_text)

# Define a LabelConcept to classify the financial risk level of the obligations
risk_classification_concept = LabelConcept(
    name="Client Financial Risk Level",
    description=(
        "Classify the financial risk level for the Client's financial obligations based on:\n"
        "- Amount size and impact on Client's cash flow\n"
        "- Payment timing and predictability for the Client\n"
        "- Penalty or liability exposure for the Client\n"
        "- Ongoing vs. one-time obligations for the Client"
    ),
    labels=["Low Risk", "Moderate Risk", "High Risk", "Critical Risk"],
    classification_type="multi_class",
    add_justifications=True,
    justification_depth="comprehensive",  # provide a comprehensive justification
    justification_max_sents=10,  # set an adequate justification length
    singular_occurrence=True,  # global risk level for the client's financial obligations
)

# Define Aspect containing the concept
financial_obligations_aspect = Aspect(
    name="Client Financial Obligations",
    description="Financial obligations that the Client must fulfill under the contract",
    concepts=[risk_classification_concept],
)

# Attach the aspect to the document
doc.add_aspects([financial_obligations_aspect])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract all data from the document
doc = llm.extract_all(doc)

# Get the extracted aspect and concept
financial_obligations_aspect = doc.get_aspect_by_name(
    "Client Financial Obligations"
)  # or `doc.aspects[0]`
risk_classification_concept = financial_obligations_aspect.get_concept_by_name(
    "Client Financial Risk Level"
)  # or `financial_obligations_aspect.concepts[0]`

# Display the extracted information

print("Extracted Client Financial Obligations:")
for extracted_item in financial_obligations_aspect.extracted_items:
    print(f"- {extracted_item.value}")

if risk_classification_concept.extracted_items:
    assert (
        len(risk_classification_concept.extracted_items) == 1
    )  # as we have set `singular_occurrence=True` on the concept
    risk_item = risk_classification_concept.extracted_items[0]
    print(f"\nClient Financial Risk Level: {risk_item.value[0]}")
    print(f"Justification: {risk_item.justification}")
else:
    print("\nRisk level could not be determined")
```

## 📊 Extracted Items

When a [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept) is extracted, it is populated with **a list of extracted items** accessible through the `.extracted_items` property. Each item is an instance of the `_LabelItem` class with the following attributes:

| Attribute              | Type                                                                                                    | Description                                                                                                                                                                                                                                                                        |
|------------------------|---------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `value`                | list[str]                                                                                               | List of selected labels (always a list for API consistency, even for multi-class with single selection)                                                                                                                                                                            |
| `justification`        | str                                                                                                     | Explanation of why these labels were selected (only if `add_justifications=True`)                                                                                                                                                                                                  |
| `probabilities`        | dict[str, float]                                                                                        | Probability of each label of the concept, e.g. `{"NDA": 0.95, "Other": 0.05}` (only if the concept is extracted by a decision model, `None` otherwise; see [🎲 Probabilities of Extracted Items](https://contextgem.shcherbak.ai/decision_models/decision_models/index.html.md#decision-models-probabilities-label)) |
| `reference_paragraphs` | list[[`Paragraph`](https://contextgem.shcherbak.ai/api/paragraphs/index.html.md#contextgem.public.paragraphs.Paragraph)] | List of paragraph objects that informed the classification (only if `add_references=True`)                                                                                                                                                                                         |
| `reference_sentences`  | list[[`Sentence`](https://contextgem.shcherbak.ai/api/sentences/index.html.md#contextgem.public.sentences.Sentence)]    | List of sentence objects that informed the classification (only if `add_references=True` and `reference_depth="sentences"`)                                                                                                                                                        |

#### NOTE
To find the position of a reference paragraph or sentence in the document, e.g. to cite it or to retrieve its surrounding context, see [📍 Locating Paragraphs and Sentences](https://contextgem.shcherbak.ai/documents/document_config/index.html.md#locating-paras-and-sents).

## 💡 Best Practices

Here are some best practices to optimize your use of [`LabelConcept`](https://contextgem.shcherbak.ai/api/concepts/index.html.md#contextgem.public.concepts.LabelConcept):

- **Choose meaningful labels**: Use clear, distinct labels that cover your classification needs without overlap.
- **Provide clear descriptions**: Explain what each classification represents and when each label should be applied.
- **Consider label granularity**: Balance between too few labels (insufficient precision) and too many labels (classification complexity).
- **Enable justifications**: Use `add_justifications=True` to understand and validate classification decisions, especially for complex or ambiguous content.
