import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from typing import Tuple, Optional, Any

def load_model(model_name: str, device: Optional[str]=None, dtype=torch.float32, use_device_map_auto: bool=False):
    device = device or ('cuda' if torch.cuda.is_available() else 'cpu')
    load_kwargs: Any = {'torch_dtype': dtype}
    if use_device_map_auto and device != 'cpu':
        load_kwargs['device_map'] = 'auto'
    model = AutoModelForCausalLM.from_pretrained(model_name, **load_kwargs)
    if not (use_device_map_auto and device != 'cpu'):
        model.to(device)
    return model

def load_tokenizer(model_name: str):
    return AutoTokenizer.from_pretrained(model_name)

def load_model_and_tokenizer(model_name: str, device: Optional[str]=None, dtype=torch.float32, use_device_map_auto: bool=False) -> Tuple:
    model = load_model(model_name, device=device, dtype=dtype, use_device_map_auto=use_device_map_auto)
    tokenizer = load_tokenizer(model_name)
    return (model, tokenizer)