Cleaned up Literature folder
This commit is contained in:
parent
73a6380034
commit
fe5eda4e05
586 changed files with 53911 additions and 2475 deletions
356
AuditGlue/System alternative/slot_manager_implementation.py
Normal file
356
AuditGlue/System alternative/slot_manager_implementation.py
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
from typing import Dict, List, Optional, Any
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
class SlotType(Enum):
|
||||
TEXT = "text"
|
||||
NUMBER = "number"
|
||||
EMAIL = "email"
|
||||
PHONE = "phone"
|
||||
DATE = "date"
|
||||
BOOLEAN = "boolean"
|
||||
CHOICE = "choice"
|
||||
|
||||
class ValidationType(Enum):
|
||||
REGEX = "regex"
|
||||
RANGE = "range"
|
||||
LENGTH = "length"
|
||||
CHOICES = "choices"
|
||||
CUSTOM = "custom"
|
||||
|
||||
class QuestionType(Enum):
|
||||
INITIAL = "initial"
|
||||
CLARIFICATION = "clarification"
|
||||
VALIDATION_ERROR = "validation_error"
|
||||
CONFIRMATION = "confirmation"
|
||||
|
||||
@dataclass
|
||||
class SlotValidation:
|
||||
validation_type: ValidationType
|
||||
validation_rule: Dict[str, Any]
|
||||
error_message: str
|
||||
|
||||
@dataclass
|
||||
class SlotQuestion:
|
||||
question_type: QuestionType
|
||||
question_text: str
|
||||
follow_up_text: Optional[str] = None
|
||||
context_conditions: Optional[Dict[str, Any]] = None
|
||||
|
||||
@dataclass
|
||||
class SlotDefinition:
|
||||
slot_name: str
|
||||
slot_type: SlotType
|
||||
is_required: bool = True
|
||||
priority: int = 1
|
||||
depends_on_slot: Optional[str] = None
|
||||
dependency_value: Optional[List[str]] = None
|
||||
validations: List[SlotValidation] = field(default_factory=list)
|
||||
questions: List[SlotQuestion] = field(default_factory=list)
|
||||
|
||||
@dataclass
|
||||
class ConversationSession:
|
||||
session_id: str
|
||||
user_id: str
|
||||
flow_id: str
|
||||
collected_slots: Dict[str, Any] = field(default_factory=dict)
|
||||
current_slot: Optional[str] = None
|
||||
context_data: Dict[str, Any] = field(default_factory=dict)
|
||||
session_status: str = "active"
|
||||
|
||||
class SlotManager:
|
||||
def __init__(self, db_connection):
|
||||
self.db = db_connection
|
||||
self.flows = {}
|
||||
self.validators = {
|
||||
ValidationType.REGEX: self._validate_regex,
|
||||
ValidationType.LENGTH: self._validate_length,
|
||||
ValidationType.RANGE: self._validate_range,
|
||||
ValidationType.CHOICES: self._validate_choices,
|
||||
}
|
||||
|
||||
def load_flow_configuration(self, flow_name: str) -> List[SlotDefinition]:
|
||||
"""Load slot configuration from database"""
|
||||
query = """
|
||||
SELECT
|
||||
sd.slot_name, sd.slot_type, sd.is_required, sd.priority,
|
||||
sd.depends_on_slot, sd.dependency_value,
|
||||
sv.validation_type, sv.validation_rule, sv.error_message,
|
||||
sq.question_type, sq.question_text, sq.follow_up_text, sq.context_conditions
|
||||
FROM conversation_flows cf
|
||||
JOIN slot_definitions sd ON cf.id = sd.flow_id
|
||||
LEFT JOIN slot_validations sv ON sd.id = sv.slot_id
|
||||
LEFT JOIN slot_questions sq ON sd.id = sq.slot_id
|
||||
WHERE cf.name = %s AND cf.is_active = true
|
||||
ORDER BY sd.priority, sd.slot_name
|
||||
"""
|
||||
|
||||
results = self.db.execute(query, (flow_name,)).fetchall()
|
||||
|
||||
# Group by slot_name
|
||||
slots_data = {}
|
||||
for row in results:
|
||||
slot_name = row['slot_name']
|
||||
if slot_name not in slots_data:
|
||||
slots_data[slot_name] = {
|
||||
'definition': {
|
||||
'slot_name': row['slot_name'],
|
||||
'slot_type': SlotType(row['slot_type']),
|
||||
'is_required': row['is_required'],
|
||||
'priority': row['priority'],
|
||||
'depends_on_slot': row['depends_on_slot'],
|
||||
'dependency_value': row['dependency_value'],
|
||||
},
|
||||
'validations': [],
|
||||
'questions': []
|
||||
}
|
||||
|
||||
# Add validation if present
|
||||
if row['validation_type']:
|
||||
validation = SlotValidation(
|
||||
validation_type=ValidationType(row['validation_type']),
|
||||
validation_rule=row['validation_rule'],
|
||||
error_message=row['error_message']
|
||||
)
|
||||
slots_data[slot_name]['validations'].append(validation)
|
||||
|
||||
# Add question if present
|
||||
if row['question_type']:
|
||||
question = SlotQuestion(
|
||||
question_type=QuestionType(row['question_type']),
|
||||
question_text=row['question_text'],
|
||||
follow_up_text=row['follow_up_text'],
|
||||
context_conditions=row['context_conditions']
|
||||
)
|
||||
slots_data[slot_name]['questions'].append(question)
|
||||
|
||||
# Convert to SlotDefinition objects
|
||||
slot_definitions = []
|
||||
for slot_data in slots_data.values():
|
||||
definition = SlotDefinition(
|
||||
**slot_data['definition'],
|
||||
validations=slot_data['validations'],
|
||||
questions=slot_data['questions']
|
||||
)
|
||||
slot_definitions.append(definition)
|
||||
|
||||
return sorted(slot_definitions, key=lambda x: x.priority)
|
||||
|
||||
def get_next_slot_to_collect(self, session: ConversationSession,
|
||||
slot_definitions: List[SlotDefinition]) -> Optional[SlotDefinition]:
|
||||
"""Determine the next slot that needs to be collected"""
|
||||
|
||||
for slot_def in slot_definitions:
|
||||
# Skip if already collected
|
||||
if slot_def.slot_name in session.collected_slots:
|
||||
continue
|
||||
|
||||
# Check if slot is required
|
||||
if not slot_def.is_required:
|
||||
continue
|
||||
|
||||
# Check dependencies
|
||||
if slot_def.depends_on_slot:
|
||||
if slot_def.depends_on_slot not in session.collected_slots:
|
||||
continue # Dependency not met
|
||||
|
||||
collected_value = session.collected_slots[slot_def.depends_on_slot]
|
||||
if slot_def.dependency_value and collected_value not in slot_def.dependency_value:
|
||||
continue # Dependency condition not met
|
||||
|
||||
return slot_def
|
||||
|
||||
return None
|
||||
|
||||
def validate_slot_value(self, slot_def: SlotDefinition,
|
||||
user_input: str) -> tuple[bool, Any, List[str]]:
|
||||
"""Validate user input for a slot"""
|
||||
errors = []
|
||||
extracted_value = user_input.strip()
|
||||
|
||||
# Type-specific extraction
|
||||
if slot_def.slot_type == SlotType.NUMBER:
|
||||
try:
|
||||
extracted_value = float(extracted_value)
|
||||
except ValueError:
|
||||
errors.append("Please enter a valid number")
|
||||
return False, user_input, errors
|
||||
|
||||
elif slot_def.slot_type == SlotType.BOOLEAN:
|
||||
lower_input = extracted_value.lower()
|
||||
if lower_input in ['yes', 'y', 'true', '1']:
|
||||
extracted_value = True
|
||||
elif lower_input in ['no', 'n', 'false', '0']:
|
||||
extracted_value = False
|
||||
else:
|
||||
errors.append("Please answer with yes or no")
|
||||
return False, user_input, errors
|
||||
|
||||
# Run validations
|
||||
for validation in slot_def.validations:
|
||||
is_valid, error_msg = self._run_validation(validation, extracted_value)
|
||||
if not is_valid:
|
||||
errors.append(error_msg)
|
||||
|
||||
return len(errors) == 0, extracted_value, errors
|
||||
|
||||
def _run_validation(self, validation: SlotValidation, value: Any) -> tuple[bool, str]:
|
||||
"""Run a specific validation rule"""
|
||||
validator = self.validators.get(validation.validation_type)
|
||||
if not validator:
|
||||
return True, ""
|
||||
|
||||
try:
|
||||
is_valid = validator(value, validation.validation_rule)
|
||||
return is_valid, validation.error_message if not is_valid else ""
|
||||
except Exception as e:
|
||||
return False, f"Validation error: {str(e)}"
|
||||
|
||||
def _validate_regex(self, value: str, rule: Dict[str, Any]) -> bool:
|
||||
pattern = rule.get('pattern', '')
|
||||
return bool(re.match(pattern, str(value)))
|
||||
|
||||
def _validate_length(self, value: str, rule: Dict[str, Any]) -> bool:
|
||||
length = len(str(value))
|
||||
min_len = rule.get('min', 0)
|
||||
max_len = rule.get('max', float('inf'))
|
||||
return min_len <= length <= max_len
|
||||
|
||||
def _validate_range(self, value: float, rule: Dict[str, Any]) -> bool:
|
||||
min_val = rule.get('min', float('-inf'))
|
||||
max_val = rule.get('max', float('inf'))
|
||||
return min_val <= value <= max_val
|
||||
|
||||
def _validate_choices(self, value: Any, rule: Dict[str, Any]) -> bool:
|
||||
choices = rule.get('choices', [])
|
||||
return value in choices
|
||||
|
||||
def get_question_for_slot(self, slot_def: SlotDefinition,
|
||||
question_type: QuestionType = QuestionType.INITIAL,
|
||||
context: Optional[Dict[str, Any]] = None) -> str:
|
||||
"""Get appropriate question text for a slot"""
|
||||
|
||||
# Find matching question
|
||||
for question in slot_def.questions:
|
||||
if question.question_type == question_type:
|
||||
# Check context conditions if present
|
||||
if question.context_conditions and context:
|
||||
if not self._check_context_conditions(question.context_conditions, context):
|
||||
continue
|
||||
|
||||
question_text = question.question_text
|
||||
if question.follow_up_text:
|
||||
question_text += f" {question.follow_up_text}"
|
||||
|
||||
return question_text
|
||||
|
||||
# Fallback to generic question
|
||||
return f"Could you please provide your {slot_def.slot_name.replace('_', ' ')}?"
|
||||
|
||||
def _check_context_conditions(self, conditions: Dict[str, Any],
|
||||
context: Dict[str, Any]) -> bool:
|
||||
"""Check if context conditions are met"""
|
||||
for key, expected_value in conditions.items():
|
||||
if key not in context:
|
||||
return False
|
||||
if context[key] != expected_value:
|
||||
return False
|
||||
return True
|
||||
|
||||
def save_conversation_session(self, session: ConversationSession):
|
||||
"""Save session state to database"""
|
||||
query = """
|
||||
INSERT INTO conversation_sessions
|
||||
(id, user_id, flow_id, session_status, current_slot, collected_slots, context_data)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
session_status = EXCLUDED.session_status,
|
||||
current_slot = EXCLUDED.current_slot,
|
||||
collected_slots = EXCLUDED.collected_slots,
|
||||
context_data = EXCLUDED.context_data,
|
||||
last_interaction = CURRENT_TIMESTAMP
|
||||
"""
|
||||
|
||||
self.db.execute(query, (
|
||||
session.session_id,
|
||||
session.user_id,
|
||||
session.flow_id,
|
||||
session.session_status,
|
||||
session.current_slot,
|
||||
json.dumps(session.collected_slots),
|
||||
json.dumps(session.context_data)
|
||||
))
|
||||
|
||||
def is_conversation_complete(self, session: ConversationSession,
|
||||
slot_definitions: List[SlotDefinition]) -> bool:
|
||||
"""Check if all required slots have been collected"""
|
||||
for slot_def in slot_definitions:
|
||||
if slot_def.is_required and slot_def.slot_name not in session.collected_slots:
|
||||
# Check if this slot should be skipped due to dependencies
|
||||
if slot_def.depends_on_slot:
|
||||
if slot_def.depends_on_slot not in session.collected_slots:
|
||||
continue
|
||||
|
||||
collected_value = session.collected_slots[slot_def.depends_on_slot]
|
||||
if slot_def.dependency_value and collected_value not in slot_def.dependency_value:
|
||||
continue
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# Example usage
|
||||
def example_conversation_flow():
|
||||
# This would be your actual database connection
|
||||
db_connection = None # Replace with real DB connection
|
||||
|
||||
slot_manager = SlotManager(db_connection)
|
||||
|
||||
# Load flow configuration
|
||||
flow_name = "customer_onboarding"
|
||||
slot_definitions = slot_manager.load_flow_configuration(flow_name)
|
||||
|
||||
# Create new session
|
||||
session = ConversationSession(
|
||||
session_id=str(uuid.uuid4()),
|
||||
user_id="user123",
|
||||
flow_id=flow_name
|
||||
)
|
||||
|
||||
# Main conversation loop
|
||||
while not slot_manager.is_conversation_complete(session, slot_definitions):
|
||||
# Get next slot to collect
|
||||
next_slot = slot_manager.get_next_slot_to_collect(session, slot_definitions)
|
||||
if not next_slot:
|
||||
break
|
||||
|
||||
# Get question for this slot
|
||||
question = slot_manager.get_question_for_slot(next_slot)
|
||||
print(f"Bot: {question}")
|
||||
|
||||
# Simulate user input
|
||||
user_input = input("User: ")
|
||||
|
||||
# Validate input
|
||||
is_valid, extracted_value, errors = slot_manager.validate_slot_value(next_slot, user_input)
|
||||
|
||||
if is_valid:
|
||||
session.collected_slots[next_slot.slot_name] = extracted_value
|
||||
print(f"Bot: Great! I've got your {next_slot.slot_name}.")
|
||||
else:
|
||||
error_question = slot_manager.get_question_for_slot(
|
||||
next_slot, QuestionType.VALIDATION_ERROR
|
||||
)
|
||||
print(f"Bot: {error_question}")
|
||||
print(f"Errors: {', '.join(errors)}")
|
||||
|
||||
# Save session
|
||||
slot_manager.save_conversation_session(session)
|
||||
|
||||
print("Bot: Thanks! I have all the information I need.")
|
||||
session.session_status = "completed"
|
||||
slot_manager.save_conversation_session(session)
|
||||
Loading…
Add table
Add a link
Reference in a new issue