""" Joint Intent + NER model class — inference-only slice. Original training script (with dataset, eval loop, plotting) lives in the training repo. This file only carries the nn.Module so the deployed pipeline can load the checkpoint without pulling in matplotlib/seqeval/sklearn/tqdm. """ import torch.nn as nn from transformers import AutoModel class JointIntentNERModel(nn.Module): """Shared BanglaBERT encoder feeding an intent head ([CLS] token) and a token-level NER head.""" def __init__(self, model_name: str, num_intents: int, num_ner_labels: int, dropout: float = 0.1): super().__init__() self.encoder = AutoModel.from_pretrained(model_name) hidden_size = self.encoder.config.hidden_size self.intent_classifier = nn.Sequential( nn.Dropout(dropout), nn.Linear(hidden_size, hidden_size // 2), nn.ReLU(), nn.Dropout(dropout), nn.Linear(hidden_size // 2, num_intents), ) self.ner_classifier = nn.Sequential( nn.Dropout(dropout), nn.Linear(hidden_size, hidden_size // 2), nn.ReLU(), nn.Dropout(dropout), nn.Linear(hidden_size // 2, num_ner_labels), ) self.num_intents = num_intents self.num_ner_labels = num_ner_labels def forward(self, input_ids, attention_mask, token_type_ids=None): outputs = self.encoder( input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids, ) cls_output = outputs.last_hidden_state[:, 0, :] intent_logits = self.intent_classifier(cls_output) ner_logits = self.ner_classifier(outputs.last_hidden_state) return intent_logits, ner_logits