diff --git a/docs/api_reference/core/audio.md b/docs/api_reference/core/audio.md new file mode 100644 index 000000000..f4f72608c --- /dev/null +++ b/docs/api_reference/core/audio.md @@ -0,0 +1,2 @@ +# Audio tools +::: marvin.core.audio \ No newline at end of file diff --git a/docs/api_reference/core/images.md b/docs/api_reference/core/images.md new file mode 100644 index 000000000..707085878 --- /dev/null +++ b/docs/api_reference/core/images.md @@ -0,0 +1,2 @@ +# Image tools +::: marvin.core.images \ No newline at end of file diff --git a/docs/api_reference/core/text.md b/docs/api_reference/core/text.md new file mode 100644 index 000000000..f91f29dd2 --- /dev/null +++ b/docs/api_reference/core/text.md @@ -0,0 +1,2 @@ +# Text tools +::: marvin.core.text \ No newline at end of file diff --git a/docs/static/css/mkdocstrings.css b/docs/static/css/mkdocstrings.css new file mode 100644 index 000000000..a3bd249c3 --- /dev/null +++ b/docs/static/css/mkdocstrings.css @@ -0,0 +1,29 @@ +/* https://mkdocstrings.github.io/python/usage/customization/#style-recommendations */ + +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Mark external links as such. */ +a.external::after, +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + mask-image: url('data:image/svg+xml,'); + -webkit-mask-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + vertical-align: middle; + position: relative; + + height: 1em; + width: 1em; + background-color: var(--md-typeset-a-color); +} + +a.external:hover::after, +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ace5c38d8..ed08ef482 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,16 +18,15 @@ nav: - Docs: - Overview: welcome/overview.md + - General purpose: + - AI Functions: core/function.md - - LLMs: + - Text and data: - Structured data: core/casting.md - Entity extraction: core/extraction.md - Classification: core/classification.md - Generating synthetic data: core/generation.md - - General purpose: - - Function: core/function.md - - Images: - Generation: core/painting.md # - Captioning: core/function.md @@ -44,10 +43,11 @@ nav: # - GitHub Digest: examples/github_digest.md - API reference: - api_reference/index.md - - AI components: - - classifier: api_reference/components/classifier.md - - function: api_reference/components/functions.md - - model: api_reference/components/models.md + - Core tools: + - Text & Data: api_reference/core/text.md + - Images: api_reference/core/images.md + - Audio: api_reference/core/audio.md + - Settings: - settings: api_reference/settings.md - Utilities: @@ -156,4 +156,5 @@ extra: extra_css: - /static/css/global.css - /static/css/badges.css - - /static/css/custom.css \ No newline at end of file + - /static/css/custom.css + - /static/css/mkdocstrings.css \ No newline at end of file diff --git a/src/marvin/core/audio.py b/src/marvin/core/audio.py index 4682b6a61..2a8994027 100644 --- a/src/marvin/core/audio.py +++ b/src/marvin/core/audio.py @@ -1,5 +1,5 @@ -from functools import wraps -from typing import Callable, Literal, TypeVar +from functools import partial, wraps +from typing import Callable, Literal, Optional, TypeVar from openai._base_client import HttpxBinaryResponseContent @@ -38,7 +38,20 @@ def speak( model_kwargs: dict = None, ): """ - Use an AI to generate audio from text. + Generates audio from text using an AI. + + This function uses an AI to generate audio from the provided text. The voice + used for the audio can be specified. + + Args: + text (str): The text to generate audio from. + voice (Literal["alloy", "echo", "fable", "onyx", "nova", "shimmer"], optional): + The voice to use for the audio. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + HttpxBinaryResponseContent: The generated audio. """ model_kwargs = model_kwargs or {} if voice is not None: @@ -51,15 +64,24 @@ def speak( return response -def speech(fn: Callable): +def speech(fn: Optional[Callable] = None, *, voice: Optional[str] = None) -> Callable: """ Function decorator that generates audio from the wrapped function's return - value. + value. The voice used for the audio can be specified. + + Args: + fn (Callable, optional): The function to wrap. Defaults to None. + voice (str, optional): The voice to use for the audio. Defaults to None. + + Returns: + Callable: The wrapped function. """ + if fn is None: + return partial(speech, voice=voice) @wraps(fn) def wrapper(*args, **kwargs): model = PythonFunction.from_function_call(fn, *args, **kwargs) - return speak(text=model.return_value) + return speak(text=model.return_value, voice=voice) return wrapper diff --git a/src/marvin/core/images.py b/src/marvin/core/images.py index a89735d91..f021cb213 100644 --- a/src/marvin/core/images.py +++ b/src/marvin/core/images.py @@ -40,10 +40,24 @@ def paint( model_kwargs: dict = None, ): """ - Generates an image from the provided instructions and context. + Generates an image based on the provided instructions and context. - By default, the DALLE-3 API modifies prompts to add detail and style. To - disable this behavior, set `literal=True`. + This function uses the DALLE-3 API to generate an image based on the provided + instructions and context. By default, the API modifies prompts to add detail + and style. This behavior can be disabled by setting `literal=True`. + + Args: + instructions (str, optional): The instructions for the image generation. + Defaults to None. + context (dict, optional): The context for the image generation. Defaults to None. + literal (bool, optional): Whether to disable the API's default behavior of + modifying prompts. Defaults to False. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + ImagesResponse: The response from the DALLE-3 API, which includes the + generated image. """ response = generate_image( prompt_template=IMAGE_PROMPT, diff --git a/src/marvin/core/text.py b/src/marvin/core/text.py index 3770c3481..0587ac29f 100644 --- a/src/marvin/core/text.py +++ b/src/marvin/core/text.py @@ -1,3 +1,7 @@ +""" +Core LLM tools for working with text and structured data. +""" + import inspect from enum import Enum from functools import partial, wraps @@ -44,6 +48,20 @@ def generate_llm_response( prompt_kwargs: dict = None, model_kwargs: dict = None, ) -> ChatResponse: + """ + Generates a language model response based on a provided prompt template. + + This function uses a language model to generate a response based on a provided prompt template. + The function supports additional arguments for the prompt and the language model. + + Args: + prompt_template (str): The template for the prompt. + prompt_kwargs (dict, optional): Additional keyword arguments for the prompt. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the language model. Defaults to None. + + Returns: + ChatResponse: The generated response from the language model. + """ model_kwargs = model_kwargs or {} prompt_kwargs = prompt_kwargs or {} messages = Transcript(content=prompt_template).render_to_messages(**prompt_kwargs) @@ -53,11 +71,11 @@ def generate_llm_response( response = MarvinClient().generate_chat(**request.model_dump()) if marvin.settings.log_verbose: logger.debug_kv("Response", response.model_dump_json(indent=2)) - tool_outputs = get_tool_outputs(request, response) + tool_outputs = _get_tool_outputs(request, response) return ChatResponse(request=request, response=response, tool_outputs=tool_outputs) -def get_tool_outputs(request: ChatRequest, response: ChatCompletion) -> list[Any]: +def _get_tool_outputs(request: ChatRequest, response: ChatCompletion) -> list[Any]: outputs = [] tool_calls = response.choices[0].message.tool_calls or [] for tool_call in tool_calls: @@ -77,6 +95,28 @@ def _generate_typed_llm_response_with_tool( prompt_kwargs: dict = None, model_kwargs: dict = None, ) -> T: + """ + Generates a language model response based on a provided prompt template and a specific tool. + + This function uses a language model to generate a response based on a + provided prompt template. The response is cast to a Python type using a tool + call. The function supports additional arguments for the prompt and the + language model. + + Args: + prompt_template (str): The template for the prompt. + type_ (Union[GenericAlias, type[T]]): The type of the response to + generate. + tool_name (str, optional): The name of the tool to use for the + generation. Defaults to None. + prompt_kwargs (dict, optional): Additional keyword arguments for the + prompt. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + T: The generated response from the language model. + """ model_kwargs = model_kwargs or {} prompt_kwargs = prompt_kwargs or {} tool = marvin.utilities.tools.tool_from_type(type_, tool_name=tool_name) @@ -105,14 +145,34 @@ def _generate_typed_llm_response_with_logit_bias( encoder: Callable[[str], list[int]] = None, max_tokens: int = 1, model_kwargs: dict = None, -) -> T: +): """ - Generates a response to a prompt that is constrained to a set of labels. + Generates a language model response with logit bias based on a provided + prompt template. + + This function uses a language model to generate a response with logit bias + based on a provided prompt template. The function supports additional + arguments for the prompt. It also allows specifying an encoder function to + be used for the generation. The LLM will be constrained to output a single number representing the 0-indexed position of the chosen option. Therefore the labels must be present (and ideally enumerated) in the prompt template, and will be provided as the kwarg `labels` + + Args: + prompt_template (str): The template for the prompt. + prompt_kwargs (dict): Additional keyword arguments for the prompt. + encoder (Callable[[str], list[int]], optional): The encoder function to + use for the generation. Defaults to None. + max_tokens (int, optional): The maximum number of tokens for the + generation. Defaults to 1. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + ChatResponse: The generated response from the language model. + """ model_kwargs = model_kwargs or {} @@ -147,7 +207,20 @@ def cast( model_kwargs: dict = None, ) -> T: """ - Convert data into the provided type. + Converts the input data into the specified type. + + This function uses a language model to convert the input data into a specified type. + The conversion process can be guided by specific instructions. The function also + supports additional arguments for the language model. + + Args: + data (str): The data to be converted. + target (type): The type to convert the data into. + instructions (str, optional): Specific instructions for the conversion. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the language model. Defaults to None. + + Returns: + T: The converted data of the specified type. """ model_kwargs = model_kwargs or {} @@ -181,7 +254,22 @@ def extract( model_kwargs: dict = None, ) -> list[T]: """ - Extract entities from the provided data. + Extracts entities of a specific type from the provided data. + + This function uses a language model to identify and extract entities of the + specified type from the input data. The extracted entities are returned as a + list. + + Args: + data (str): The data from which to extract entities. + target (type): The type of entities to extract. + instructions (str, optional): Specific instructions for the extraction. + Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + list: A list of extracted entities of the specified type. """ model_kwargs = model_kwargs or {} return _generate_typed_llm_response_with_tool( @@ -199,11 +287,23 @@ def classify( model_kwargs: dict = None, ) -> T: """ - Classify the provided information as of the provided labels. + Classifies the provided data based on the provided labels. - This uses a logit bias to constrain the LLM response to a single token. It - is highly efficient for classification tasks and will always return one of - the provided responses. + This function uses a language model with a logit bias to classify the input + data. The logit bias constrains the language model's response to a single + token, making this function highly efficient for classification tasks. The + function will always return one of the provided labels. + + Args: + data (str): The data to be classified. + labels (Union[Enum, list[T], type]): The labels to classify the data into. + instructions (str, optional): Specific instructions for the + classification. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + T: The label that the data was classified into. """ model_kwargs = model_kwargs or {} @@ -222,10 +322,22 @@ def generate( model_kwargs: dict = None, ) -> list[T]: """ - Generate a list of n items of the provided type or instructions. + Generates a list of 'n' items of the provided type or based on instructions. + + Either a type or instructions must be provided. If instructions are provided + without a type, the type is assumed to be a string. The function generates at + least 'n' items. - Either a type or instructions must be provided. If instructions are - provided without a type, the type is assumed to be a string. + Args: + type_ (type, optional): The type of items to generate. Defaults to None. + instructions (str, optional): Instructions for the generation. Defaults to None. + n (int, optional): The number of items to generate. Defaults to 1. + temperature (float, optional): The temperature for the generation. Defaults to 1. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + list: A list of generated items. """ if type_ is None and instructions is None: @@ -250,13 +362,25 @@ def generate( def fn(func: Callable = None, model_kwargs: dict = None): """ - A decorator that converts a Python function into an AI function. + Converts a Python function into an AI function using a decorator. + + This decorator allows a Python function to be converted into an AI function. + The AI function uses a language model to generate its output. + + Args: + func (Callable, optional): The function to be converted. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + Callable: The converted AI function. - @fn - def list_fruit(n:int) -> list[str]: - '''generates a list of n fruit''' + Example: + @fn + def list_fruit(n:int) -> list[str]: + '''generates a list of n fruit''' - list_fruit(3) # ['apple', 'banana', 'orange'] + list_fruit(3) # ['apple', 'banana', 'orange'] """ if func is None: @@ -312,12 +436,33 @@ class Model(BaseModel): @classmethod def from_text(cls, text: str, model_kwargs: dict = None, **kwargs) -> "Model": - """Async text constructor""" + """ + Class method to create an instance of the model from a natural language string. + + Args: + text (str): The natural language string to convert into an instance of the model. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + **kwargs: Additional keyword arguments to pass to the model's constructor. + + Returns: + Model: An instance of the model. + """ ai_kwargs = cast(text, cls, model_kwargs=model_kwargs, **kwargs) ai_kwargs.update(kwargs) return cls(**ai_kwargs) def __init__(self, text: str = None, *, model_kwargs: dict = None, **kwargs): + """ + Initializes an instance of the model. + + Args: + text (str, optional): The natural language string to convert into an + instance of the model. Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + **kwargs: Additional keyword arguments to pass to the model's constructor. + """ ai_kwargs = kwargs if text is not None: ai_kwargs = cast(text, type(self), model_kwargs=model_kwargs).model_dump() @@ -335,8 +480,10 @@ def classifier(cls=None, *, instructions=None, model_kwargs=None): Args: cls (Enum, optional): The Enum class to be decorated. - instructions (str, optional): Instructions for the AI on how to perform the classification. - model_kwargs (dict, optional): Additional keyword arguments to pass to the model. + instructions (str, optional): Instructions for the AI on + how to perform the classification. + model_kwargs (dict, optional): Additional keyword + arguments to pass to the model. Returns: Enum: The decorated Enum class with modified __call__ method. @@ -376,8 +523,19 @@ def model( type_: Union[Type[M], None] = None, model_kwargs: dict = None ) -> Union[Type[M], Callable[[Type[M]], Type[M]]]: """ - Class decorator for instantiating a Pydantic model from a string. Equivalent - to subclassing Model. + Class decorator for instantiating a Pydantic model from a string. + + This decorator allows a Pydantic model to be instantiated from a string. It's + equivalent to subclassing the Model class. + + Args: + type_ (Union[Type[M], None], optional): The type of the Pydantic model. + Defaults to None. + model_kwargs (dict, optional): Additional keyword arguments for the + language model. Defaults to None. + + Returns: + Union[Type[M], Callable[[Type[M]], Type[M]]]: The decorated Pydantic model. """ model_kwargs = model_kwargs or {}