Skip to content

LLM Map

dandy.llm.Map

Bases: BaseModel

Source code in dandy/map/map.py
def __init__(self, valid_map: Dict[str, Any], **data: Any) -> None:
    super().__init__(
        valid_map=valid_map,
        **data
    )

valid_map instance-attribute

keyed_choices property

keyed_choices_dict property

keyed_choices_str property

__getitem__

Source code in dandy/map/map.py
def __getitem__(self, item):
    return self.valid_map[item]

as_enum

Source code in dandy/map/map.py
def as_enum(self) -> Enum:
    enum_choices = {}
    for key, value in self._keyed_map.items():
        enum_choices[value[0]] = key

    return Enum(f'{self.__class__.__name__}Enum', enum_choices)

model_post_init

Source code in dandy/map/map.py
def model_post_init(self, __context: Any) -> None:
    self.process_valid_to_keyed()

get_selected_value

Source code in dandy/map/map.py
def get_selected_value(self, choice_key: str) -> Any:
    return self._keyed_map[choice_key][1]

process_valid_to_keyed

Source code in dandy/map/map.py
def process_valid_to_keyed(self):
    for i, (choice, value) in enumerate(self.valid_map.items(), start=1):
        key = str(i)
        if isinstance(value, dict):
            self._keyed_map[key] = (choice, self.process_valid_to_keyed())
        else:
            self._keyed_map[key] = (choice, value)

dandy.llm.BaseLlmMap

Bases: BaseLlmProcessor[MapKeysIntel], ABC

config = 'DEFAULT' class-attribute instance-attribute

config_options = LlmConfigOptions() class-attribute instance-attribute

instructions_prompt = Prompt() class-attribute instance-attribute

intel_class = MapKeysIntel class-attribute instance-attribute

map_keys_description instance-attribute

map instance-attribute

__init_subclass__

Source code in dandy/llm/map/llm_map.py
def __init_subclass__(cls):
    super().__init_subclass__()

    if cls.map_keys_description is None:
        raise MapCriticalException(f'{cls.__name__} `map_keys_description` is not set.')

    if cls.map is None:
        raise MapCriticalException(f'{cls.__name__} `map` is not set.')

    if cls._map_enum is None:
        cls._map_enum = cls.map.as_enum()

process classmethod

Source code in dandy/llm/map/llm_map.py
@classmethod
def process(
        cls,
        prompt: Union[Prompt, str],
        max_return_values: int | None = None,
) -> MapValuesIntel:
    return cls.process_map_to_intel(
        cls.map,
        prompt,
        max_return_values
    )

process_map_to_intel classmethod

Source code in dandy/llm/map/llm_map.py
@classmethod
def process_map_to_intel(
        cls,
        map: Map,
        prompt: Union[Prompt, str],
        max_return_values: int | None = None
) -> MapValuesIntel:
    map_values_intel = MapValuesIntel()

    for map_enum in cls.process_prompt_to_intel(map, prompt, max_return_values):
        map_value = map.get_selected_value(map_enum.value)

        if isinstance(map_value, type):
            if issubclass(map_value, BaseLlmMap):
                map_values_intel.extend(
                    map_value.process(
                        prompt,
                        max_return_values
                    ).values
                )
            else:
                map_values_intel.append(map_value)

        elif isinstance(map_value, Map):
            map_values_intel.extend(
                cls.process_map_to_intel(
                    map_value,
                    prompt,
                    max_return_values
                ).values
            )
        else:
            map_values_intel.append(map_value)

    return map_values_intel

process_prompt_to_intel classmethod

Source code in dandy/llm/map/llm_map.py
@classmethod
def process_prompt_to_intel(
        cls,
        map: Map,
        prompt: Union[Prompt, str],
        max_return_values: int | None = None,
) -> MapKeysIntel:

    if max_return_values is not None and max_return_values > 1:
        key_str = 'keys'
        intel_class = MapKeysIntel[list[cls._map_enum]]
    else:
        key_str = 'key'
        intel_class = MapKeyIntel[cls._map_enum]

    system_prompt = Prompt()
    system_prompt.prompt(cls.instructions_prompt)
    system_prompt.text(f'You\'re an "{cls.map_keys_description}" assistant')

    system_prompt.line_break()

    system_prompt.text(
        f'Read through all of the "{cls.map_keys_description}" and return the numbered {key_str} that match information relevant to the user\'s input.')

    system_prompt.line_break()

    if max_return_values is not None and max_return_values > 0:
        if max_return_values == 1:
            system_prompt.text(f'You must return exactly one numbered {key_str}.')
        else:
            system_prompt.text(
                f'Return up to a maximum of {max_return_values} numbered {key_str} and return at least one at a minimum.')
    else:
        system_prompt.text(
            f'Return the numbered {key_str} you find that are most relevant and return at least one.')

    system_prompt.line_break()
    system_prompt.heading(f'"{cls.map_keys_description}"')
    system_prompt.line_break()

    system_prompt.dict(map.keyed_choices_dict)

    llm_service = llm_configs[cls.config].generate_service(
        llm_options=cls.config_options
    )

    return_keys_intel = cls._process_return_keys_intel(
        llm_service.process_prompt_to_intel(
            prompt=prompt if isinstance(prompt, Prompt) else Prompt(prompt),
            intel_class=intel_class,
            system_prompt=system_prompt
        )
    )

    while llm_service.has_retry_attempts_available:
        try:
            cls._validate_return_keys_intel(return_keys_intel, max_return_values)
            break

        except MapNoKeysRecoverableException as error:
            recorder_add_llm_failure_event(error, llm_service.event_id)

            if llm_service.has_retry_attempts_available:
                return_keys_intel = llm_service.retry_process_request_to_intel(
                    retry_event_description=f'Map keys intel object came back empty, retrying with no keys prompt.',
                    retry_user_prompt=map_no_key_error_prompt()
                )
            else:
                raise error

        except MapToManyKeysRecoverableException as error:
            recorder_add_llm_failure_event(error, llm_service.event_id)

            if llm_service.has_retry_attempts_available:
                return_keys_intel = llm_service.retry_process_request_to_intel(
                    retry_event_description=f'Map keys intel object came back with to many keys, retrying with to many keys prompt.',
                    retry_user_prompt=map_max_key_count_error_prompt(
                        returned_count=len(return_keys_intel),
                        max_count=max_return_values if max_return_values is not None else 0,
                    )
                )

            else:
                raise error

    try:
        cls._validate_return_keys_intel(return_keys_intel, max_return_values)

    except MapRecoverableException as error:
        recorder_add_llm_failure_event(error, llm_service.event_id)
        raise error

    return return_keys_intel

process_to_future classmethod

Source code in dandy/llm/map/llm_map.py
@classmethod
def process_to_future(cls, *args, **kwargs) -> AsyncFuture[MapValuesIntel]:
    return AsyncFuture[MapValuesIntel](cls.process, *args, **kwargs)