Dialogue Systems
Dialogue systems enable human-computer interaction through natural language. They range from task-oriented systems (booking flights) to open-domain chatbots (casual conversation).
Dialogue System Types
| Type | Goal | Example | Complexity |
|---|---|---|---|
| Task-oriented | Complete a specific task | Book a hotel | High |
| Open-domain | Casual conversation | ChatGPT | Very high |
| Question-answering | Answer specific questions | FAQ bot | Medium |
| Recommendation | Suggest items | Movie recommender | Medium |
| Information retrieval | Find information | Search assistant | Medium |
Task-Oriented Dialogue Components
Dialogue State Tracking (DST)
DST maintains the current state of the conversation by tracking user intents and slot values.
from transformers import AutoModelForTokenClassification, AutoTokenizer
class DialogueStateTracker:
def __init__(self):
self.state = {
"intent": None,
"slots": {},
"history": []
}
self.nlu_model = None
self.tokenizer = None
def update(self, utterance):
# Parse intent and slots
intent, slots = self.parse_nlu(utterance)
self.state["intent"] = intent
self.state["slots"].update(slots)
self.state["history"].append(utterance)
return self.state
def parse_nlu(self, utterance):
# Simple rule-based NLU for demonstration
intent = "inform"
slots = {}
if "book" in utterance.lower():
intent = "book_hotel"
elif "search" in utterance.lower():
intent = "search_hotel"
# Extract slot values
if "cheap" in utterance.lower():
slots["price_range"] = "cheap"
if "london" in utterance.lower():
slots["city"] = "london"
if "tomorrow" in utterance.lower():
slots["date"] = "tomorrow"
return intent, slots
def get_database_query(self):
return self.state["slots"]
dst = DialogueStateTracker()
print(dst.update("I want to book a cheap hotel in london"))
# {'intent': 'book_hotel', 'slots': {'price_range': 'cheap', 'city': 'london'}}
Intent Classification and Slot Filling
DfJoint Intent and Slot Filling
from transformers import AutoModelForSequenceClassification
import torch
class IntentClassifier:
def __init__(self, model_name="bert-base-uncased"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSequenceClassification.from_pretrained(
model_name, num_labels=10
)
self.intent_labels = [
"greeting", "farewell", "book_hotel", "search_hotel",
"cancel_booking", "ask_price", "ask_location",
"complaint", "thank_you", "other"
]
def classify(self, text):
inputs = self.tokenizer(text, return_tensors="pt", truncation=True)
with torch.no_grad():
outputs = self.model(**inputs)
probs = torch.softmax(outputs.logits, dim=-1)
intent_idx = torch.argmax(probs, dim=-1).item()
confidence = probs[0, intent_idx].item()
return {
"intent": self.intent_labels[intent_idx],
"confidence": confidence
}
# Slot filling with token classification
class SlotFiller:
def __init__(self, model_name="bert-base-uncased"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForTokenClassification.from_pretrained(
model_name, num_labels=9
)
self.slot_labels = ["O", "B-HOTEL", "I-HOTEL", "B-CITY", "I-CITY",
"B-PRICE", "I-PRICE", "B-DATE", "I-DATE"]
def extract_slots(self, text):
inputs = self.tokenizer(text, return_tensors="pt", truncation=True)
with torch.no_grad():
outputs = self.model(**inputs)
predictions = torch.argmax(outputs.logits, dim=-1)
tokens = self.tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
slots = [(t, self.slot_labels[p]) for t, p in
zip(tokens, predictions[0]) if not t.startswith("[")]
return slots
Open-Domain Dialogue
Open-domain chatbots engage in unconstrained conversation.
from transformers import AutoModelForCausalLM, AutoTokenizer
import random
class ChatBot:
def __init__(self, model_name="microsoft/DialoGPT-medium"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForCausalLM.from_pretrained(model_name)
self.chat_history_ids = None
def respond(self, user_input):
# Encode user input
new_input_ids = self.tokenizer.encode(
user_input + self.tokenizer.eos_token,
return_tensors='pt'
)
# Append to chat history
if self.chat_history_ids is not None:
input_ids = torch.cat(
[self.chat_history_ids, new_input_ids], dim=-1
)
else:
input_ids = new_input_ids
# Generate response
self.chat_history_ids = self.model.generate(
input_ids,
max_length=1000,
pad_token_id=self.tokenizer.eos_token_id,
temperature=0.7,
top_k=50,
top_p=0.95,
do_sample=True,
no_repeat_ngram_size=3
)
response = self.tokenizer.decode(
self.chat_history_ids[:, input_ids.shape[-1]:][0],
skip_special_tokens=True
)
return response
chatbot = ChatBot()
print(chatbot.respond("Hello!"))
print(chatbot.respond("How are you today?"))
Dialogue Evaluation
| Metric | Type | Measures |
|---|---|---|
| Perplexity | Automatic | Language quality |
| BLEU | Automatic | Response relevance |
| Distinct-n | Automatic | Response diversity |
| Human evaluation | Manual | Overall quality |
| Coherence | Manual | Logical consistency |
| Engagement | Manual | Conversation quality |
DfDistinct-n (Diversity)
Multi-Turn Dialogue Management
class DialogueManager:
def __init__(self):
self.state = {}
self.history = []
self.turn_count = 0
def process_turn(self, user_utterance):
self.turn_count += 1
# Update state with new information
intent, entities = self.parse_utterance(user_utterance)
self.state.update(entities)
# Select action based on state
action = self.select_action(intent)
# Generate response
response = self.generate_response(action)
self.history.append({
"user": user_utterance,
"bot": response,
"state": self.state.copy()
})
return response
def parse_utterance(self, text):
# Placeholder for actual NLU
return "inform", {}
def select_action(self, intent):
action_map = {
"greeting": "respond_greeting",
"inform": "request_additional_info",
"book_hotel": "check_availability",
}
return action_map.get(intent, "fallback")
def generate_response(self, action):
response_templates = {
"respond_greeting": "Hello! How can I help you today?",
"request_additional_info": "Could you provide more details?",
"check_availability": "Let me check available options for you.",
"fallback": "I'm sorry, I didn't understand that."
}
return response_templates.get(action, "I'm here to help.")