diff --git a/.nojekyll b/.nojekyll index ea3835d..f2472b0 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -dd8cf27c \ No newline at end of file +66eff987 \ No newline at end of file diff --git a/get-started.html b/get-started.html index 1c69299..a81abc7 100644 --- a/get-started.html +++ b/get-started.html @@ -119,6 +119,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/index.html b/index.html index 497e26b..6fb3d6b 100644 --- a/index.html +++ b/index.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/prompt-design.html b/prompt-design.html index d342936..fb83943 100644 --- a/prompt-design.html +++ b/prompt-design.html @@ -156,6 +156,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • @@ -251,7 +255,7 @@

    Best practices

    Code generation

    Let’s explore prompt design for a simple code generation task:

    -
    +
    from chatlas import ChatAnthropic, ChatOpenAI
     
     question = """
    @@ -262,11 +266,11 @@ 

    Code generation

    Basic flavour

    When I don’t provide a system prompt, I sometimes get answers in a different language (like R):

    -
    +
    chat = ChatAnthropic()
     _ = chat.chat(question)
    -
    +
    @@ -284,14 +288,14 @@

    Basic flavour

    ))) # Alternative base R approach -aggregate(. ~ age + sex, data = df[,c("age", "sex", letters[1:26])], +aggregate(. ~ age + sex, data = df[,c("age", "sex", letters)], FUN = function(x) c(mean = mean(x), median = median(x)))

    This will: 1. Group the data by age and sex 2. Calculate both mean and median for each variable a through z 3. Handle missing values with na.rm = TRUE 4. Return a dataframe with results for each age-sex combination

    The output will have columns for age, sex, and mean/median values for each variable.

    I can ensure that I always get Python code by providing a system prompt:

    -
    +
    chat.system_prompt = "You are a helpful Python (not R) programming assistant."
     _ = chat.chat(question)
    @@ -299,34 +303,29 @@

    Basic flavour


    -

    Here’s how to compute mean and median for variables a through z in Python using pandas:

    +

    Here’s how to compute mean and median for variables a through z using Python, likely with pandas:

    import pandas as pd
     
     # Assuming your data is in a DataFrame called df
    -# Group by age and sex, then calculate mean and median for all variables a through z
    -result = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median'])
    -
    -# If you want to handle missing values:
    -result = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg({
    -    col: ['mean', 'median'] for col in list('abcdefghijklmnopqrstuvwxyz')
    -}).fillna(0)  # or use .dropna() instead of fillna() if you prefer to remove NaN values
    -
    -# To make the output more readable, you can flatten the column names:
    -result.columns = [f'{col}_{stat}' for col, stat in result.columns]
    -

    This will: 1. Group your data by age and sex 2. Calculate mean and median for each variable from ‘a’ to ‘z’ 3. Return a DataFrame where: - The index will be the age and sex combinations - The columns will be each variable’s mean and median - Column names will be in the format ‘variable_statistic’ (e.g., ‘a_mean’, ‘a_median’, etc.)

    -

    Example output might look like:

    -
                    a_mean  a_median  b_mean  b_median  ...  z_mean  z_median
    -age sex                                            ...
    -20  M          23.5    24.0      45.2    46.0      ...  12.3    12.0
    -    F          22.1    21.0      44.8    45.0      ...  11.9    12.0
    -21  M          24.2    25.0      46.1    46.0      ...  12.5    13.0
    -    F          23.8    24.0      45.9    46.0      ...  12.2    12.0
    -...
    +result = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median']) + +# If you want to reset the index to make age and sex regular columns +result = result.reset_index() + +# Alternative way with more explicit column selection: +columns_to_analyze = [chr(i) for i in range(ord('a'), ord('z')+1)] +result = df.groupby(['age', 'sex'])[columns_to_analyze].agg(['mean', 'median'])
    +

    This will: 1. Group the data by age and sex 2. Calculate both mean and median for each variable from ‘a’ to ‘z’ 3. Handle missing values automatically 4. Create a multi-level column structure where each variable has both mean and median

    +

    The resulting DataFrame will have: - age and sex as index (unless reset_index() is used) - A hierarchical column structure where each variable (a-z) has both mean and median values

    +

    If you need to handle missing values differently, you can modify the aggregation like this:

    +
    result = df.groupby(['age', 'sex'])[columns_to_analyze].agg({
    +    col: ['mean', 'median'] for col in columns_to_analyze
    +}).dropna()  # or use .fillna(0) to replace NAs with zeros

    Note that I’m using both a system prompt (which defines the general behaviour) and a user prompt (which asks the specific question). You could put all of the content in the user prompt and get similar results, but I think it’s helpful to use both to cleanly divide the general framing of the response from the specific questions that you want to ask.

    Since I’m mostly interested in the code, I ask it to drop the explanation:

    -
    +
    chat.system_prompt = """
       You are a helpful Python (not R) programming assistant.
       Just give me the code without any text explanation.
    @@ -339,12 +338,13 @@ 

    Basic flavour


    import pandas as pd
     
    -result = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median'])
    -result.columns = [f'{col}_{stat}' for col, stat in result.columns]
    +columns_to_analyze = list('abcdefghijklmnopqrstuvwxyz') +result = df.groupby(['age', 'sex'])[columns_to_analyze].agg(['mean', 'median']) +result = result.reset_index()

    In this case, I seem to mostly get pandas code. But if you want a different style, you can ask for it:

    -
    +
    chat.system_prompt = """
       You are a helpful Python (not R) programming assistant who prefers polars to pandas.
       Just give me the code without any text explanation.
    @@ -357,18 +357,17 @@ 

    Basic flavour


    import polars as pl
     
    -result = df.groupby(['age', 'sex']).agg([
    -    pl.col(c).mean().alias(f'{c}_mean') for c in 'abcdefghijklmnopqrstuvwxyz'
    -] + [
    -    pl.col(c).median().alias(f'{c}_median') for c in 'abcdefghijklmnopqrstuvwxyz'
    -])
    +columns_to_analyze = list('abcdefghijklmnopqrstuvwxyz') +result = (df.groupby(['age', 'sex']) + .agg([pl.col(col).mean().alias(f'{col}_mean') for col in columns_to_analyze] + + [pl.col(col).median().alias(f'{col}_median') for col in columns_to_analyze]))

    Be explicit

    If there’s something about the output that you don’t like, you can try being more explicit about it. For example, the code isn’t styled quite how I like, so I provide more details about what I do want:

    -
    +
    chat.system_prompt = """
       You are a helpful Python (not R) programming assistant who prefers siuba to pandas.
       Just give me the code. I don't want any explanation or sample data.
    @@ -382,21 +381,22 @@ 

    Be explicit


    -
    from siuba import *
    -from siuba.dply.vector import *
    -
    -result = (df 
    -  >> group_by(_.age, _.sex)
    -  >> summarize(**{
    -    f"{col}_{stat}": call(stat, _[col])
    -    for col in "abcdefghijklmnopqrstuvwxyz"
    -    for stat in ["mean", "median"]
    -  }))
    +
    from siuba import _, group_by, summarize
    +from siuba.siu import call
    +import pandas as pd
    +
    +result = (df
    +  >> group_by(_.age, _.sex)
    +  >> summarize(**{
    +    f"{col}_{agg}": call(agg, _[col])
    +    for col in "abcdefghijklmnopqrstuvwxyz"
    +    for agg in ["mean", "median"]
    +  }))

    This still doesn’t yield exactly the code that I’d write, but it’s prety close.

    You could provide a different prompt if you were looking for more explanation of the code:

    -
    +
    chat.system_prompt = """
       You are an an expert Python (not R) programmer and a warm and supportive teacher.
       Help me understand the code you produce by explaining each function call with
    @@ -411,24 +411,22 @@ 

    Be explicit


    import pandas as pd
     
    -# Create list of letters a-z to use as column names
    +# Generate list of letter columns a through z
     cols = list('abcdefghijklmnopqrstuvwxyz')
     
    -# Group by age & sex, compute mean and median for all letter columns
    -result = df.groupby(['age', 'sex'])[cols].agg([
    -    'mean',    # Calculate mean for each column
    -    'median'   # Calculate median for each column
    -])
    -
    -# Flatten the multi-level column names for readability 
    -result.columns = [f'{col}_{stat}' for col, stat in result.columns]
    +# Group by age and sex, calculate mean and median for each letter column +result = (df + .groupby(['age', 'sex'])[cols] # Group by age/sex and select letter columns + .agg(['mean', 'median']) # Calculate both mean and median + .reset_index() # Convert age/sex back to regular columns +)

    Teach it about new features

    You can imagine LLMs as being a sort of an average of the internet at a given point in time. That means they will provide popular answers, which will tend to reflect older coding styles (either because the new features aren’t in their index, or the older features are so much more popular). So if you want your code to use specific newer language features, you might need to provide the examples yourself:

    -
    +
    chat.system_prompt = """
       You are an expert R programmer.
       Just give me the code; no explanation in text.
    @@ -471,7 +469,7 @@ 

    Structured data

    Getting started

    My overall goal is to turn a list of ingredients, like the following, into a nicely structured JSON that I can then analyse in Python (e.g. compute the total weight, scale the recipe up or down, or convert the units from volumes to weights).

    -
    +
    ingredients = """
       ¾ cup (150g) dark brown sugar
       2 large eggs
    @@ -487,7 +485,7 @@ 

    Getting started

    (This isn’t the ingredient list for a real recipe but it includes a sampling of styles that I encountered in my project.)

    If you don’t have strong feelings about what the data structure should look like, you can start with a very loose prompt and see what you get back. I find this a useful pattern for underspecified problems where the heavy lifting lies with precisely defining the problem you want to solve. Seeing the LLM’s attempt to create a data structure gives me something to react to, rather than having to start from a blank page.

    -
    +
    instruct_json = """
       You're an expert baker who also loves JSON. I am going to give you a list of
       ingredients and your job is to return nicely structured JSON. Just return the
    @@ -500,7 +498,53 @@ 

    Getting started


    -

    { “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: “¾ cup”, “weight”: “150g” }, { “name”: “large eggs”, “quantity”: “2” }, { “name”: “sour cream”, “quantity”: “¾ cup”, “weight”: “165g” }, { “name”: “unsalted butter”, “quantity”: “½ cup”, “weight”: “113g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: “1 teaspoon” }, { “name”: “kosher salt”, “quantity”: “¾ teaspoon” }, { “name”: “neutral oil”, “quantity”: “⅓ cup”, “volume”: “80ml” }, { “name”: “all-purpose flour”, “quantity”: “1½ cups”, “weight”: “190g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons” } ] }

    +
    {
    +  "ingredients": [
    +    {
    +      "name": "dark brown sugar",
    +      "amount": "¾ cup",
    +      "weightInGrams": 150
    +    },
    +    {
    +      "name": "eggs",
    +      "amount": "2 large"
    +    },
    +    {
    +      "name": "sour cream",
    +      "amount": "¾ cup",
    +      "weightInGrams": 165
    +    },
    +    {
    +      "name": "unsalted butter",
    +      "amount": "½ cup",
    +      "weightInGrams": 113,
    +      "state": "melted"
    +    },
    +    {
    +      "name": "vanilla extract",
    +      "amount": "1 teaspoon"
    +    },
    +    {
    +      "name": "kosher salt",
    +      "amount": "¾ teaspoon"
    +    },
    +    {
    +      "name": "neutral oil",
    +      "amount": "⅓ cup",
    +      "volumeInMilliliters": 80
    +    },
    +    {
    +      "name": "all-purpose flour",
    +      "amount": "1½ cups",
    +      "weightInGrams": 190
    +    },
    +    {
    +      "name": "sugar",
    +      "amount": "150g plus 1½ teaspoons",
    +      "weightInGrams": 150
    +    }
    +  ]
    +}

    (I don’t know if the additional colour, “You’re an expert baker who also loves JSON”, does anything, but I like to think this helps the LLM get into the right mindset of a very nerdy baker.)

    @@ -508,103 +552,153 @@

    Getting started

    Provide examples

    This isn’t a bad start, but I prefer to cook with weight and I only want to see volumes if weight isn’t available so I provide a couple of examples of what I’m looking for. I was pleasantly suprised that I can provide the input and output examples in such a loose format.

    -
    -
    instruct_weight = """
    -  Here are some examples of the sort of output I'm looking for:
    -
    -  ¾ cup (150g) dark brown sugar
    -  {"name": "dark brown sugar", "quantity": 150, "unit": "g"}
    -
    -  ⅓ cup (80ml) neutral oil
    -  {"name": "neutral oil", "quantity": 80, "unit": "ml"}
    -
    -  2 t ground cinnamon
    -  {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon"}
    -"""
    -
    -chat.system_prompt = instruct_json + "\n" + instruct_weight
    -_ = chat.chat(ingredients)
    +
    +
    instruct_weight = """
    +  Here are some examples of the sort of output I'm looking for:
    +
    +  ¾ cup (150g) dark brown sugar
    +  {"name": "dark brown sugar", "quantity": 150, "unit": "g"}
    +
    +  ⅓ cup (80ml) neutral oil
    +  {"name": "neutral oil", "quantity": 80, "unit": "ml"}
    +
    +  2 t ground cinnamon
    +  {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon"}
    +"""
    +
    +chat.system_prompt = instruct_json + "\n" + instruct_weight
    +_ = chat.chat(ingredients)


    -

    { “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: 150, “unit”: “g” }, { “name”: “large eggs”, “quantity”: 2, “unit”: “count” }, { “name”: “sour cream”, “quantity”: 165, “unit”: “g” }, { “name”: “unsalted butter”, “quantity”: 113, “unit”: “g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: 1, “unit”: “teaspoon” }, { “name”: “kosher salt”, “quantity”: ¾, “unit”: “teaspoon” }, { “name”: “neutral oil”, “quantity”: 80, “unit”: “ml” }, { “name”: “all-purpose flour”, “quantity”: 190, “unit”: “g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons”, “unit”: “g” } ] }

    +
    {
    +  "ingredients": [
    +    {
    +      "name": "dark brown sugar",
    +      "quantity": 150,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "large eggs",
    +      "quantity": 2,
    +      "unit": "count"
    +    },
    +    {
    +      "name": "sour cream",
    +      "quantity": 165,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "unsalted butter",
    +      "quantity": 113,
    +      "unit": "g",
    +      "state": "melted"
    +    },
    +    {
    +      "name": "vanilla extract",
    +      "quantity": 1,
    +      "unit": "teaspoon"
    +    },
    +    {
    +      "name": "kosher salt",
    +      "quantity": 0.75,
    +      "unit": "teaspoon"
    +    },
    +    {
    +      "name": "neutral oil",
    +      "quantity": 80,
    +      "unit": "ml"
    +    },
    +    {
    +      "name": "all-purpose flour",
    +      "quantity": 190,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "sugar",
    +      "quantity": 150,
    +      "unit": "g",
    +      "additional": "plus 1½ teaspoons"
    +    }
    +  ]
    +}

    Just providing the examples seems to work remarkably well. But I found it useful to also include a description of what the examples are trying to accomplish. I’m not sure if this helps the LLM or not, but it certainly makes it easier for me to understand the organisation and check that I’ve covered the key pieces I’m interested in.

    -
    -
    instruct_weight = """
    -  * If an ingredient has both weight and volume, extract only the weight:
    -
    -  ¾ cup (150g) dark brown sugar
    -  [
    -    {"name": "dark brown sugar", "quantity": 150, "unit": "g"}
    -  ]
    -
    -* If an ingredient only lists a volume, extract that.
    -
    -  2 t ground cinnamon
    -  ⅓ cup (80ml) neutral oil
    -  [
    -    {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon"},
    -    {"name": "neutral oil", "quantity": 80, "unit": "ml"}
    -  ]
    -"""
    +
    +
    instruct_weight = """
    +  * If an ingredient has both weight and volume, extract only the weight:
    +
    +  ¾ cup (150g) dark brown sugar
    +  [
    +    {"name": "dark brown sugar", "quantity": 150, "unit": "g"}
    +  ]
    +
    +* If an ingredient only lists a volume, extract that.
    +
    +  2 t ground cinnamon
    +  ⅓ cup (80ml) neutral oil
    +  [
    +    {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon"},
    +    {"name": "neutral oil", "quantity": 80, "unit": "ml"}
    +  ]
    +"""

    This structure also allows me to give the LLMs a hint about how I want multiple ingredients to be stored, i.e. as an JSON array.

    I then iterated on the prompt, looking at the results from different recipes to get a sense of what the LLM was getting wrong. Much of this felt like I was iterating on my own understanding of the problem as I didn’t start by knowing exactly how I wanted the data. For example, when I started out I didn’t really think about all the various ways that ingredients are specified. For later analysis, I always want quantities to be number, even if they were originally fractions, or the if the units aren’t precise (like a pinch). It made me to realise that some ingredients are unitless.

    -
    -
    instruct_unit = """
    -* If the unit uses a fraction, convert it to a decimal.
    -
    -  ⅓ cup sugar
    -  ½ teaspoon salt
    -  [
    -    {"name": "dark brown sugar", "quantity": 0.33, "unit": "cup"},
    -    {"name": "salt", "quantity": 0.5, "unit": "teaspoon"}
    -  ]
    -
    -* Quantities are always numbers
    -
    -  pinch of kosher salt
    -  [
    -    {"name": "kosher salt", "quantity": 1, "unit": "pinch"}
    -  ]
    -
    -* Some ingredients don't have a unit.
    -  2 eggs
    -  1 lime
    -  1 apple
    -  [
    -    {"name": "egg", "quantity": 2},
    -    {"name": "lime", "quantity": 1},
    -    {"name", "apple", "quantity": 1}
    -  ]
    -"""
    +
    +
    instruct_unit = """
    +* If the unit uses a fraction, convert it to a decimal.
    +
    +  ⅓ cup sugar
    +  ½ teaspoon salt
    +  [
    +    {"name": "dark brown sugar", "quantity": 0.33, "unit": "cup"},
    +    {"name": "salt", "quantity": 0.5, "unit": "teaspoon"}
    +  ]
    +
    +* Quantities are always numbers
    +
    +  pinch of kosher salt
    +  [
    +    {"name": "kosher salt", "quantity": 1, "unit": "pinch"}
    +  ]
    +
    +* Some ingredients don't have a unit.
    +  2 eggs
    +  1 lime
    +  1 apple
    +  [
    +    {"name": "egg", "quantity": 2},
    +    {"name": "lime", "quantity": 1},
    +    {"name", "apple", "quantity": 1}
    +  ]
    +"""

    You might want to take a look at the full prompt to see what I ended up with.

    Structured data

    Now that I’ve iterated to get a data structure I like, it seems useful to formalise it and tell the LLM exactly what I’m looking for when dealing with structured data. This guarantees that the LLM will only return JSON, that the JSON will have the fields that you expect, and that chatlas will convert it into an Python data structure for you.

    -
    -
    from pydantic import BaseModel, Field
    -
    -class Ingredient(BaseModel):
    -    "Ingredient name"
    -    name: str = Field(description="Ingredient name")
    -    quantity: float
    -    unit: str | None = Field(description="Unit of measurement")
    -
    -class Ingredients(BaseModel):
    -    items: list[Ingredient]
    -
    -chat.system_prompt = instruct_json + "\n" + instruct_weight
    -chat.extract_data(ingredients, data_model=Ingredients)
    +
    +
    from pydantic import BaseModel, Field
    +
    +class Ingredient(BaseModel):
    +    "Ingredient name"
    +    name: str = Field(description="Ingredient name")
    +    quantity: float
    +    unit: str | None = Field(description="Unit of measurement")
    +
    +class Ingredients(BaseModel):
    +    items: list[Ingredient]
    +
    +chat.system_prompt = instruct_json + "\n" + instruct_weight
    +chat.extract_data(ingredients, data_model=Ingredients)
    {'items': [{'name': 'dark brown sugar', 'quantity': 150, 'unit': 'g'},
    -  {'name': 'large eggs', 'quantity': 2, 'unit': 'count'},
    +  {'name': 'eggs', 'quantity': 2, 'unit': 'large'},
       {'name': 'sour cream', 'quantity': 165, 'unit': 'g'},
       {'name': 'unsalted butter', 'quantity': 113, 'unit': 'g'},
       {'name': 'vanilla extract', 'quantity': 1, 'unit': 'teaspoon'},
    @@ -618,48 +712,98 @@ 

    Structured data

    Capturing raw input

    One thing that I’d do next time would also be to include the raw ingredient names in the output. This doesn’t make much difference in this simple example but it makes it much easier to align the input with the output and to start developing automated measures of how well my prompt is doing.

    -
    -
    instruct_weight_input = """
    -  * If an ingredient has both weight and volume, extract only the weight:
    -
    -    ¾ cup (150g) dark brown sugar
    -    [
    -      {"name": "dark brown sugar", "quantity": 150, "unit": "g", "input": "¾ cup (150g) dark brown sugar"}
    -    ]
    -
    -  * If an ingredient only lists a volume, extract that.
    -
    -    2 t ground cinnamon
    -    ⅓ cup (80ml) neutral oil
    -    [
    -      {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon", "input": "2 t ground cinnamon"},
    -      {"name": "neutral oil", "quantity": 80, "unit": "ml", "input": "⅓ cup (80ml) neutral oil"}
    -    ]
    -"""
    +
    +
    instruct_weight_input = """
    +  * If an ingredient has both weight and volume, extract only the weight:
    +
    +    ¾ cup (150g) dark brown sugar
    +    [
    +      {"name": "dark brown sugar", "quantity": 150, "unit": "g", "input": "¾ cup (150g) dark brown sugar"}
    +    ]
    +
    +  * If an ingredient only lists a volume, extract that.
    +
    +    2 t ground cinnamon
    +    ⅓ cup (80ml) neutral oil
    +    [
    +      {"name": "ground cinnamon", "quantity": 2, "unit": "teaspoon", "input": "2 t ground cinnamon"},
    +      {"name": "neutral oil", "quantity": 80, "unit": "ml", "input": "⅓ cup (80ml) neutral oil"}
    +    ]
    +"""

    I think this is particularly important if you’re working with even less structured text. For example, imagine you had this text:

    -
    -
    recipe = """
    -  In a large bowl, cream together one cup of softened unsalted butter and a
    -  quarter cup of white sugar until smooth. Beat in an egg and 1 teaspoon of
    -  vanilla extract. Gradually stir in 2 cups of all-purpose flour until the
    -  dough forms. Finally, fold in 1 cup of semisweet chocolate chips. Drop
    -  spoonfuls of dough onto an ungreased baking sheet and bake at 350°F (175°C)
    -  for 10-12 minutes, or until the edges are lightly browned. Let the cookies
    -  cool on the baking sheet for a few minutes before transferring to a wire
    -  rack to cool completely. Enjoy!
    -"""
    +
    +
    recipe = """
    +  In a large bowl, cream together one cup of softened unsalted butter and a
    +  quarter cup of white sugar until smooth. Beat in an egg and 1 teaspoon of
    +  vanilla extract. Gradually stir in 2 cups of all-purpose flour until the
    +  dough forms. Finally, fold in 1 cup of semisweet chocolate chips. Drop
    +  spoonfuls of dough onto an ungreased baking sheet and bake at 350°F (175°C)
    +  for 10-12 minutes, or until the edges are lightly browned. Let the cookies
    +  cool on the baking sheet for a few minutes before transferring to a wire
    +  rack to cool completely. Enjoy!
    +"""

    Including the input text in the output makes it easier to see if it’s doing a good job:

    -
    -
    chat.system_prompt = instruct_json + "\n" + instruct_weight_input
    -_ = chat.chat(ingredients)
    +
    +
    chat.system_prompt = instruct_json + "\n" + instruct_weight_input
    +_ = chat.chat(ingredients)


    -

    { “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: 150, “unit”: “g” }, { “name”: “large eggs”, “quantity”: 2, “unit”: “count” }, { “name”: “sour cream”, “quantity”: 165, “unit”: “g” }, { “name”: “unsalted butter”, “quantity”: 113, “unit”: “g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: 1, “unit”: “teaspoon” }, { “name”: “kosher salt”, “quantity”: 0.75, “unit”: “teaspoon” }, { “name”: “neutral oil”, “quantity”: 80, “unit”: “ml” }, { “name”: “all-purpose flour”, “quantity”: 190, “unit”: “g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons”, “unit”: “g” } ] }

    +
    {
    +  "ingredients": [
    +    {
    +      "name": "dark brown sugar",
    +      "quantity": 150,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "eggs",
    +      "quantity": 2,
    +      "unit": "large"
    +    },
    +    {
    +      "name": "sour cream",
    +      "quantity": 165,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "unsalted butter",
    +      "quantity": 113,
    +      "unit": "g",
    +      "state": "melted"
    +    },
    +    {
    +      "name": "vanilla extract",
    +      "quantity": 1,
    +      "unit": "teaspoon"
    +    },
    +    {
    +      "name": "kosher salt",
    +      "quantity": 0.75,
    +      "unit": "teaspoon"
    +    },
    +    {
    +      "name": "neutral oil",
    +      "quantity": 80,
    +      "unit": "ml"
    +    },
    +    {
    +      "name": "all-purpose flour",
    +      "quantity": 190,
    +      "unit": "g"
    +    },
    +    {
    +      "name": "sugar",
    +      "quantity": 150,
    +      "unit": "g",
    +      "additional": "plus 1½ teaspoons"
    +    }
    +  ]
    +}

    When I ran it while writing this vignette, it seemed to be working out the weight of the ingredients specified in volume, even though the prompt specifically asks it not to. This may suggest I need to broaden my examples.

    @@ -667,12 +811,12 @@

    Capturing raw input

    Token usage

    -
    -
    from chatlas import token_usage
    -token_usage()
    +
    +
    from chatlas import token_usage
    +token_usage()
    -
    [{'name': 'Anthropic', 'input': 6504, 'output': 1270},
    - {'name': 'OpenAI', 'input': 2909, 'output': 1043}]
    +
    [{'name': 'Anthropic', 'input': 5755, 'output': 1114},
    + {'name': 'OpenAI', 'input': 3121, 'output': 1089}]
    diff --git a/rag.html b/rag.html new file mode 100644 index 0000000..93299ac --- /dev/null +++ b/rag.html @@ -0,0 +1,773 @@ + + + + + + + + + +rag – chatlas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    + + + + +
    + +
    +
    +

    Retrieval-Augmented Generation (RAG)

    +
    + + + +
    + + + + +
    + + + +
    + + +

    Retrieval-Augmented Generation (RAG) helps LLMs gain the context they need to accurately answer a question. Nowadays, LLMs are trained on a vast amount of data, but they can’t possibly know everything, especially when it comes to real-time or sensitive information that isn’t publicly available. In this article, we’ll walk through a simple example of how to leverage RAG in combination with chatlas.

    +

    The core idea of RAG is fairly simple, yet general: given a set of documents and a user query, find the document(s) that are the most “similar” to the query and supply those documents as additional context to the LLM. The LLM can then use this context to generate a response to the user query. There are many ways to measure similarity between a query and a document, but one common approach is to use embeddings. Embeddings are dense, low-dimensional vectors that represent the semantic content of a piece of text. By comparing the embeddings of the query and each document, we can compute a similarity score that tells us how closely related the query is to each document.

    +

    There are also many different ways to generate embeddings, but one popular method is to use pre-trained models like Sentence Transformers. Different models are trained on different datasets and thus have different strengths and weaknesses, so it’s worth experimenting with a few to see which one works best for your particular use case. In our example, we’ll use the all-MiniLM-L12-v2 model, which is a popular choice thanks to its balance of speed and accuracy.

    +
    +
    from sentence_transformers import SentenceTransformer
    +
    +embed_model = SentenceTransformer("sentence-transformers/all-MiniLM-L12-v2")
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Supplied with an embedding model, we can now compute embeddings for each document in our set and for a user_query, then compare the query embedding to each document embedding to find the most similar document(s). A common way to measure similarity between two vectors is to compute the cosine similarity. The following code demonstrates how to do this:

    +
    +
    import numpy as np
    +
    +# Our list of documents (one document per list element)
    +documents = [
    +    "The Python programming language was created by Guido van Rossum.",
    +    "Python is known for its simple, readable syntax.",
    +    "Python supports multiple programming paradigms.",
    +]
    +
    +# Compute embeddings for each document (do this once for performance reasons)
    +embeddings = [embed_model.encode([doc])[0] for doc in documents]
    +
    +
    +def get_top_k_similar_documents(
    +    user_query,
    +    documents,
    +    embeddings,
    +    embed_model,
    +    top_k=3,
    +):
    +    # Compute embedding for the user query
    +    query_embedding = embed_model.encode([user_query])[0]
    +
    +    # Calculate cosine similarity between the query and each document
    +    similarities = np.dot(embeddings, query_embedding) / (
    +        np.linalg.norm(embeddings, axis=1) * np.linalg.norm(query_embedding)
    +    )
    +
    +    # Get the top-k most similar documents
    +    top_indices = np.argsort(similarities)[-top_k:][::-1]
    +    return [documents[i] for i in top_indices]
    +
    +
    +user_query = "Who created Python?"
    +
    +top_docs = get_top_k_similar_documents(
    +    user_query,
    +    documents,
    +    embeddings,
    +    embed_model,
    +    top_k=3,
    +)
    +
    +

    And, now that we have the most similar documents, we can supply them to the LLM as context for generating a response to the user query. Here’s how we might do that using chatlas:

    +
    +
    from chatlas import ChatAnthropic
    +
    +chat = ChatAnthropic(
    +    system_prompt="""
    +    You are a helpful AI assistant. Using the provided context, 
    +    answer the user's question. If you cannot answer the question based on the 
    +    context, say so.
    +"""
    +)
    +
    +_ = chat.chat(
    +    f"Context: {top_docs}\nQuestion: {user_query}"
    +)
    +
    +
    +
    +
    +


    +

    Based on the context, Python was created by Guido van Rossum.

    +
    +
    + + + +
    + + +
    + + + + + \ No newline at end of file diff --git a/reference/Chat.html b/reference/Chat.html index 9c944f1..920dba0 100644 --- a/reference/Chat.html +++ b/reference/Chat.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatAnthropic.html b/reference/ChatAnthropic.html index bb0dfb4..1f5c6cc 100644 --- a/reference/ChatAnthropic.html +++ b/reference/ChatAnthropic.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatAzureOpenAI.html b/reference/ChatAzureOpenAI.html index 0a789c0..f6d26f0 100644 --- a/reference/ChatAzureOpenAI.html +++ b/reference/ChatAzureOpenAI.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatBedrockAnthropic.html b/reference/ChatBedrockAnthropic.html index 3b33633..54f864a 100644 --- a/reference/ChatBedrockAnthropic.html +++ b/reference/ChatBedrockAnthropic.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatGithub.html b/reference/ChatGithub.html index 3c3f6c4..04f20db 100644 --- a/reference/ChatGithub.html +++ b/reference/ChatGithub.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatGoogle.html b/reference/ChatGoogle.html index daf8718..63aa7b1 100644 --- a/reference/ChatGoogle.html +++ b/reference/ChatGoogle.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatGroq.html b/reference/ChatGroq.html index 641085b..7ee383c 100644 --- a/reference/ChatGroq.html +++ b/reference/ChatGroq.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatOllama.html b/reference/ChatOllama.html index 309c4e9..1430da2 100644 --- a/reference/ChatOllama.html +++ b/reference/ChatOllama.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatOpenAI.html b/reference/ChatOpenAI.html index 169622c..4a69f41 100644 --- a/reference/ChatOpenAI.html +++ b/reference/ChatOpenAI.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/ChatPerplexity.html b/reference/ChatPerplexity.html index 9c55796..82e8347 100644 --- a/reference/ChatPerplexity.html +++ b/reference/ChatPerplexity.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/Provider.html b/reference/Provider.html index d213d82..da8916d 100644 --- a/reference/Provider.html +++ b/reference/Provider.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/Tool.html b/reference/Tool.html index be78f16..59424ea 100644 --- a/reference/Tool.html +++ b/reference/Tool.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/Turn.html b/reference/Turn.html index 399e8fa..4f7d0a9 100644 --- a/reference/Turn.html +++ b/reference/Turn.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/content_image_file.html b/reference/content_image_file.html index b3bcf0a..a5becd5 100644 --- a/reference/content_image_file.html +++ b/reference/content_image_file.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/content_image_plot.html b/reference/content_image_plot.html index d4f7f2b..0dd1bf9 100644 --- a/reference/content_image_plot.html +++ b/reference/content_image_plot.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/content_image_url.html b/reference/content_image_url.html index 467efbf..f05e179 100644 --- a/reference/content_image_url.html +++ b/reference/content_image_url.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/image_file.html b/reference/image_file.html index 2e70356..e9d5ffd 100644 --- a/reference/image_file.html +++ b/reference/image_file.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/image_plot.html b/reference/image_plot.html index 778bd11..fca3ae7 100644 --- a/reference/image_plot.html +++ b/reference/image_plot.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/image_url.html b/reference/image_url.html index bef3085..361aa58 100644 --- a/reference/image_url.html +++ b/reference/image_url.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/index.html b/reference/index.html index 39719f8..0f26ec6 100644 --- a/reference/index.html +++ b/reference/index.html @@ -119,6 +119,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/interpolate.html b/reference/interpolate.html index 68bb239..e8ad939 100644 --- a/reference/interpolate.html +++ b/reference/interpolate.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/interpolate_file.html b/reference/interpolate_file.html index 288a76e..e7f6fdd 100644 --- a/reference/interpolate_file.html +++ b/reference/interpolate_file.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/token_usage.html b/reference/token_usage.html index 4f443fc..b2e6772 100644 --- a/reference/token_usage.html +++ b/reference/token_usage.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ChatResponse.html b/reference/types.ChatResponse.html index c70ced9..02c0622 100644 --- a/reference/types.ChatResponse.html +++ b/reference/types.ChatResponse.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ChatResponseAsync.html b/reference/types.ChatResponseAsync.html index 1c0f44a..cd52b8a 100644 --- a/reference/types.ChatResponseAsync.html +++ b/reference/types.ChatResponseAsync.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.Content.html b/reference/types.Content.html index 6d6b5f5..188fac7 100644 --- a/reference/types.Content.html +++ b/reference/types.Content.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentImage.html b/reference/types.ContentImage.html index a5b33e2..d4f8fe8 100644 --- a/reference/types.ContentImage.html +++ b/reference/types.ContentImage.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentImageInline.html b/reference/types.ContentImageInline.html index 0954d2b..8292c24 100644 --- a/reference/types.ContentImageInline.html +++ b/reference/types.ContentImageInline.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentImageRemote.html b/reference/types.ContentImageRemote.html index 9852633..0b34668 100644 --- a/reference/types.ContentImageRemote.html +++ b/reference/types.ContentImageRemote.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentJson.html b/reference/types.ContentJson.html index bb1da8d..b818a40 100644 --- a/reference/types.ContentJson.html +++ b/reference/types.ContentJson.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentText.html b/reference/types.ContentText.html index 19cfe8d..1f83c2b 100644 --- a/reference/types.ContentText.html +++ b/reference/types.ContentText.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentToolRequest.html b/reference/types.ContentToolRequest.html index 1817e71..4466678 100644 --- a/reference/types.ContentToolRequest.html +++ b/reference/types.ContentToolRequest.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ContentToolResult.html b/reference/types.ContentToolResult.html index 7f212a1..a1e99cd 100644 --- a/reference/types.ContentToolResult.html +++ b/reference/types.ContentToolResult.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.ImageContentTypes.html b/reference/types.ImageContentTypes.html index f220eb6..3242e13 100644 --- a/reference/types.ImageContentTypes.html +++ b/reference/types.ImageContentTypes.html @@ -119,6 +119,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.MISSING.html b/reference/types.MISSING.html index 4e41d1b..bfb889d 100644 --- a/reference/types.MISSING.html +++ b/reference/types.MISSING.html @@ -119,6 +119,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.MISSING_TYPE.html b/reference/types.MISSING_TYPE.html index dc1d068..b0bc4ee 100644 --- a/reference/types.MISSING_TYPE.html +++ b/reference/types.MISSING_TYPE.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.SubmitInputArgsT.html b/reference/types.SubmitInputArgsT.html index 7db8270..464d29d 100644 --- a/reference/types.SubmitInputArgsT.html +++ b/reference/types.SubmitInputArgsT.html @@ -119,6 +119,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/reference/types.TokenUsage.html b/reference/types.TokenUsage.html index 124e189..c428adc 100644 --- a/reference/types.TokenUsage.html +++ b/reference/types.TokenUsage.html @@ -153,6 +153,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • diff --git a/search.json b/search.json index 851c364..ad69960 100644 --- a/search.json +++ b/search.json @@ -1,857 +1,908 @@ [ { - "objectID": "reference/types.ChatResponseAsync.html", - "href": "reference/types.ChatResponseAsync.html", - "title": "types.ChatResponseAsync", + "objectID": "rag.html", + "href": "rag.html", + "title": "Retrieval-Augmented Generation (RAG)", "section": "", - "text": "types.ChatResponseAsync(self, generator)\nChat response (async) object.\nAn object that, when displayed, will simulatenously consume (if not already consumed) and display the response in a streaming fashion.\nThis is useful for interactive use: if the object is displayed, it can be viewed as it is being generated. And, if the object is not displayed, it can act like an iterator that can be consumed by something else.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.\n\n\n\n\n\n\nconsumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).\n\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponseAsync.get_content()\nGet the chat response content as a string.", - "crumbs": [ - "Reference", - "User-facing types", - "types.ChatResponseAsync" - ] + "text": "Retrieval-Augmented Generation (RAG) helps LLMs gain the context they need to accurately answer a question. Nowadays, LLMs are trained on a vast amount of data, but they can’t possibly know everything, especially when it comes to real-time or sensitive information that isn’t publicly available. In this article, we’ll walk through a simple example of how to leverage RAG in combination with chatlas.\nThe core idea of RAG is fairly simple, yet general: given a set of documents and a user query, find the document(s) that are the most “similar” to the query and supply those documents as additional context to the LLM. The LLM can then use this context to generate a response to the user query. There are many ways to measure similarity between a query and a document, but one common approach is to use embeddings. Embeddings are dense, low-dimensional vectors that represent the semantic content of a piece of text. By comparing the embeddings of the query and each document, we can compute a similarity score that tells us how closely related the query is to each document.\nThere are also many different ways to generate embeddings, but one popular method is to use pre-trained models like Sentence Transformers. Different models are trained on different datasets and thus have different strengths and weaknesses, so it’s worth experimenting with a few to see which one works best for your particular use case. In our example, we’ll use the all-MiniLM-L12-v2 model, which is a popular choice thanks to its balance of speed and accuracy.\n\nfrom sentence_transformers import SentenceTransformer\n\nembed_model = SentenceTransformer(\"sentence-transformers/all-MiniLM-L12-v2\")\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nSupplied with an embedding model, we can now compute embeddings for each document in our set and for a user_query, then compare the query embedding to each document embedding to find the most similar document(s). A common way to measure similarity between two vectors is to compute the cosine similarity. The following code demonstrates how to do this:\n\nimport numpy as np\n\n# Our list of documents (one document per list element)\ndocuments = [\n \"The Python programming language was created by Guido van Rossum.\",\n \"Python is known for its simple, readable syntax.\",\n \"Python supports multiple programming paradigms.\",\n]\n\n# Compute embeddings for each document (do this once for performance reasons)\nembeddings = [embed_model.encode([doc])[0] for doc in documents]\n\n\ndef get_top_k_similar_documents(\n user_query,\n documents,\n embeddings,\n embed_model,\n top_k=3,\n):\n # Compute embedding for the user query\n query_embedding = embed_model.encode([user_query])[0]\n\n # Calculate cosine similarity between the query and each document\n similarities = np.dot(embeddings, query_embedding) / (\n np.linalg.norm(embeddings, axis=1) * np.linalg.norm(query_embedding)\n )\n\n # Get the top-k most similar documents\n top_indices = np.argsort(similarities)[-top_k:][::-1]\n return [documents[i] for i in top_indices]\n\n\nuser_query = \"Who created Python?\"\n\ntop_docs = get_top_k_similar_documents(\n user_query,\n documents,\n embeddings,\n embed_model,\n top_k=3,\n)\n\nAnd, now that we have the most similar documents, we can supply them to the LLM as context for generating a response to the user query. Here’s how we might do that using chatlas:\n\nfrom chatlas import ChatAnthropic\n\nchat = ChatAnthropic(\n system_prompt=\"\"\"\n You are a helpful AI assistant. Using the provided context, \n answer the user's question. If you cannot answer the question based on the \n context, say so.\n\"\"\"\n)\n\n_ = chat.chat(\n f\"Context: {top_docs}\\nQuestion: {user_query}\"\n)\n\n\n\n\n\nBased on the context, Python was created by Guido van Rossum." }, { - "objectID": "reference/types.ChatResponseAsync.html#attributes", - "href": "reference/types.ChatResponseAsync.html#attributes", - "title": "types.ChatResponseAsync", + "objectID": "reference/ChatGoogle.html", + "href": "reference/ChatGoogle.html", + "title": "ChatGoogle", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.", + "text": "ChatGoogle(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n kwargs=None,\n)\nChat with a Google Gemini model.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nTo use Google’s models (i.e., Gemini), you’ll need to sign up for an account and get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGoogle requires the google-generativeai package (e.g., pip install google-generativeai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGoogle\n\nchat = ChatGoogle(api_key=os.getenv(\"GOOGLE_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GOOGLE_API_KEY environment variable.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the genai.GenerativeModel constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.\n\n\n\n\n\n\nChatGoogle currently doesn’t work with streaming tools.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGoogle(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGOOGLE_API_KEY=...\nfrom chatlas import ChatGoogle\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGoogle()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GOOGLE_API_KEY=...", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponseAsync" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/types.ChatResponseAsync.html#properties", - "href": "reference/types.ChatResponseAsync.html#properties", - "title": "types.ChatResponseAsync", + "objectID": "reference/ChatGoogle.html#prerequisites", + "href": "reference/ChatGoogle.html#prerequisites", + "title": "ChatGoogle", "section": "", - "text": "consumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).", + "text": "API key\n\n\n\nTo use Google’s models (i.e., Gemini), you’ll need to sign up for an account and get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGoogle requires the google-generativeai package (e.g., pip install google-generativeai).", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponseAsync" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/types.ChatResponseAsync.html#methods", - "href": "reference/types.ChatResponseAsync.html#methods", - "title": "types.ChatResponseAsync", + "objectID": "reference/ChatGoogle.html#examples", + "href": "reference/ChatGoogle.html#examples", + "title": "ChatGoogle", "section": "", - "text": "Name\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponseAsync.get_content()\nGet the chat response content as a string.", + "text": "import os\nfrom chatlas import ChatGoogle\n\nchat = ChatGoogle(api_key=os.getenv(\"GOOGLE_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponseAsync" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/Provider.html", - "href": "reference/Provider.html", - "title": "Provider", + "objectID": "reference/ChatGoogle.html#parameters", + "href": "reference/ChatGoogle.html#parameters", + "title": "ChatGoogle", "section": "", - "text": "Provider\nProvider()\nA model provider interface for a Chat.\nThis abstract class defines the interface a model provider must implement in order to be used with a Chat instance. The provider is responsible for performing the actual chat completion, and for handling the streaming of the completion results.\nNote that this class is exposed for developers who wish to implement their own provider. In general, you should not need to interact with this class directly.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GOOGLE_API_KEY environment variable.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the genai.GenerativeModel constructor.\nNone", "crumbs": [ "Reference", - "Implement a model provider", - "Provider" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/types.SubmitInputArgsT.html", - "href": "reference/types.SubmitInputArgsT.html", - "title": "types.SubmitInputArgsT", + "objectID": "reference/ChatGoogle.html#returns", + "href": "reference/ChatGoogle.html#returns", + "title": "ChatGoogle", "section": "", - "text": "types.SubmitInputArgsT\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat() method of a Chat instance.", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", - "User-facing types", - "types.SubmitInputArgsT" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/Tool.html", - "href": "reference/Tool.html", - "title": "Tool", + "objectID": "reference/ChatGoogle.html#limitations", + "href": "reference/ChatGoogle.html#limitations", + "title": "ChatGoogle", "section": "", - "text": "Tool(self, func, *, model=None)\nDefine a tool\nDefine a Python function for use by a chatbot. The function will always be invoked in the current Python process.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfunc\nCallable[…, Any] | Callable[…, Awaitable[Any]]\nThe function to be invoked when the tool is called.\nrequired\n\n\nmodel\nOptional[type[BaseModel]]\nA Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\nNone", + "text": "ChatGoogle currently doesn’t work with streaming tools.", "crumbs": [ "Reference", - "Tool calling", - "Tool" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/Tool.html#parameters", - "href": "reference/Tool.html#parameters", - "title": "Tool", + "objectID": "reference/ChatGoogle.html#note", + "href": "reference/ChatGoogle.html#note", + "title": "ChatGoogle", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nfunc\nCallable[…, Any] | Callable[…, Awaitable[Any]]\nThe function to be invoked when the tool is called.\nrequired\n\n\nmodel\nOptional[type[BaseModel]]\nA Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\nNone", + "text": "Pasting an API key into a chat constructor (e.g., ChatGoogle(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGOOGLE_API_KEY=...\nfrom chatlas import ChatGoogle\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGoogle()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GOOGLE_API_KEY=...", "crumbs": [ "Reference", - "Tool calling", - "Tool" + "Chat model providers", + "ChatGoogle" ] }, { - "objectID": "reference/types.ChatResponse.html", - "href": "reference/types.ChatResponse.html", - "title": "types.ChatResponse", + "objectID": "reference/content_image_url.html", + "href": "reference/content_image_url.html", + "title": "content_image_url", "section": "", - "text": "types.ChatResponse(self, generator)\nChat response object.\nAn object that, when displayed, will simulatenously consume (if not already consumed) and display the response in a streaming fashion.\nThis is useful for interactive use: if the object is displayed, it can be viewed as it is being generated. And, if the object is not displayed, it can act like an iterator that can be consumed by something else.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.\n\n\n\n\n\n\nconsumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).\n\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponse.get_content()\nGet the chat response content as a string.", + "text": "content_image_url(url, detail='auto')\nEncode image content from a URL for chat input.\nThis function is used to prepare image URLs for input to the chatbot. It can handle both regular URLs and data URLs.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid.", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponse" + "Image input", + "content_image_url" ] }, { - "objectID": "reference/types.ChatResponse.html#attributes", - "href": "reference/types.ChatResponse.html#attributes", - "title": "types.ChatResponse", + "objectID": "reference/content_image_url.html#parameters", + "href": "reference/content_image_url.html#parameters", + "title": "content_image_url", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponse" + "Image input", + "content_image_url" ] }, { - "objectID": "reference/types.ChatResponse.html#properties", - "href": "reference/types.ChatResponse.html#properties", - "title": "types.ChatResponse", + "objectID": "reference/content_image_url.html#returns", + "href": "reference/content_image_url.html#returns", + "title": "content_image_url", "section": "", - "text": "consumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).", + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponse" + "Image input", + "content_image_url" ] }, { - "objectID": "reference/types.ChatResponse.html#methods", - "href": "reference/types.ChatResponse.html#methods", - "title": "types.ChatResponse", + "objectID": "reference/content_image_url.html#examples", + "href": "reference/content_image_url.html#examples", + "title": "content_image_url", "section": "", - "text": "Name\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponse.get_content()\nGet the chat response content as a string.", + "text": "from chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)", "crumbs": [ "Reference", - "User-facing types", - "types.ChatResponse" + "Image input", + "content_image_url" ] }, { - "objectID": "reference/interpolate.html", - "href": "reference/interpolate.html", - "title": "interpolate", + "objectID": "reference/content_image_url.html#raises", + "href": "reference/content_image_url.html#raises", + "title": "content_image_url", "section": "", - "text": "interpolate(prompt, *, variables=None, variable_start='{{', variable_end='}}')\nInterpolate variables into a prompt\nThis is a light-weight wrapper around the Jinja2 templating engine, making it easier to interpolate dynamic data into a prompt template. Compared to f-strings, which expects you to wrap dynamic values in { }, this function expects { } instead, making it easier to include Python code and JSON in your prompt.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nprompt\nstr\nThe prompt to interpolate (as a string).\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.\n\n\n\n\n\n\nfrom chatlas import interpolate\n\nx = 1\ninterpolate(\"The value of `x` is: {{ x }}\")", + "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid.", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate" + "Image input", + "content_image_url" ] }, { - "objectID": "reference/interpolate.html#parameters", - "href": "reference/interpolate.html#parameters", - "title": "interpolate", + "objectID": "reference/types.ContentImageInline.html", + "href": "reference/types.ContentImageInline.html", + "title": "types.ContentImageInline", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nprompt\nstr\nThe prompt to interpolate (as a string).\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'", + "text": "types.ContentImageInline(self, content_type, data=None)\nInline image content.\nThis is the return type for content_image_file and content_image_plot. It’s not meant to be used directly.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ncontent_type\nImageContentTypes\nThe content type of the image.\nrequired\n\n\ndata\nOptional[str]\nThe base64-encoded image data.\nNone", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate" + "User-facing types", + "types.ContentImageInline" ] }, { - "objectID": "reference/interpolate.html#returns", - "href": "reference/interpolate.html#returns", - "title": "interpolate", + "objectID": "reference/types.ContentImageInline.html#parameters", + "href": "reference/types.ContentImageInline.html#parameters", + "title": "types.ContentImageInline", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\ncontent_type\nImageContentTypes\nThe content type of the image.\nrequired\n\n\ndata\nOptional[str]\nThe base64-encoded image data.\nNone", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate" + "User-facing types", + "types.ContentImageInline" ] }, { - "objectID": "reference/interpolate.html#examples", - "href": "reference/interpolate.html#examples", - "title": "interpolate", + "objectID": "reference/image_plot.html", + "href": "reference/image_plot.html", + "title": "content_image_plot", "section": "", - "text": "from chatlas import interpolate\n\nx = 1\ninterpolate(\"The value of `x` is: {{ x }}\")", - "crumbs": [ - "Reference", - "Prompt interpolation", - "interpolate" - ] + "text": "content_image_plot(width=768, height=768, dpi=72)\nEncode the current matplotlib plot as an image for chat input.\nThis function captures the current matplotlib plot, resizes it to the specified dimensions, and prepares it for chat input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)" }, { - "objectID": "reference/types.TokenUsage.html", - "href": "reference/types.TokenUsage.html", - "title": "types.TokenUsage", + "objectID": "reference/image_plot.html#parameters", + "href": "reference/image_plot.html#parameters", + "title": "content_image_plot", "section": "", - "text": "types.TokenUsage\ntypes.TokenUsage()\nToken usage for a given provider (name).", - "crumbs": [ - "Reference", - "User-facing types", - "types.TokenUsage" - ] + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72" }, { - "objectID": "reference/types.ContentImage.html", - "href": "reference/types.ContentImage.html", - "title": "types.ContentImage", + "objectID": "reference/image_plot.html#returns", + "href": "reference/image_plot.html#returns", + "title": "content_image_plot", "section": "", - "text": "types.ContentImage\ntypes.ContentImage()\nBase class for image content.\nThis class is not meant to be used directly. Instead, use content_image_url, content_image_file, or content_image_plot.", + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." + }, + { + "objectID": "reference/image_plot.html#raises", + "href": "reference/image_plot.html#raises", + "title": "content_image_plot", + "section": "", + "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer." + }, + { + "objectID": "reference/image_plot.html#examples", + "href": "reference/image_plot.html#examples", + "title": "content_image_plot", + "section": "", + "text": "from chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)" + }, + { + "objectID": "reference/types.ContentJson.html", + "href": "reference/types.ContentJson.html", + "title": "types.ContentJson", + "section": "", + "text": "types.ContentJson(self, value)\nJSON content\nThis content type primarily exists to signal structured data extraction (i.e., data extracted via Chat’s .extract_data() method)\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nvalue\ndict[str, Any]\nThe JSON data extracted\nrequired", "crumbs": [ "Reference", "User-facing types", - "types.ContentImage" + "types.ContentJson" ] }, { - "objectID": "reference/types.ImageContentTypes.html", - "href": "reference/types.ImageContentTypes.html", - "title": "types.ImageContentTypes", + "objectID": "reference/types.ContentJson.html#parameters", + "href": "reference/types.ContentJson.html#parameters", + "title": "types.ContentJson", "section": "", - "text": "types.ImageContentTypes\ntypes.ImageContentTypes\nAllowable content types for images.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nvalue\ndict[str, Any]\nThe JSON data extracted\nrequired", "crumbs": [ "Reference", "User-facing types", - "types.ImageContentTypes" + "types.ContentJson" ] }, { - "objectID": "reference/ChatPerplexity.html", - "href": "reference/ChatPerplexity.html", - "title": "ChatPerplexity", + "objectID": "reference/token_usage.html", + "href": "reference/token_usage.html", + "title": "token_usage", "section": "", - "text": "ChatPerplexity(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.perplexity.ai/',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on perplexity.ai.\nPerplexity AI is a platform for running LLMs that are capable of searching the web in real-time to help them answer questions with information that may not have been available when the model was trained.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://www.perplexity.ai to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatPerplexity requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatPerplexity\n\nchat = ChatPerplexity(api_key=os.getenv(\"PERPLEXITY_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the PERPLEXITY_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Perplexity’s API.\n'https://api.perplexity.ai/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around chatlas.ChatOpenAI with the defaults tweaked for perplexity.ai.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatPerplexity(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nPERPLEXITY_API_KEY=...\nfrom chatlas import ChatPerplexity\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatPerplexity()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport PERPLEXITY_API_KEY=...", + "text": "token_usage()\nReport on token usage in the current session\nCall this function to find out the cumulative number of tokens that you have sent and received in the current session.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[TokenUsage] | None\nA list of dictionaries with the following keys: “name”, “input”, and “output”. If no tokens have been logged, then None is returned.", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "Query token usage", + "token_usage" ] }, { - "objectID": "reference/ChatPerplexity.html#prerequisites", - "href": "reference/ChatPerplexity.html#prerequisites", - "title": "ChatPerplexity", + "objectID": "reference/token_usage.html#returns", + "href": "reference/token_usage.html#returns", + "title": "token_usage", "section": "", - "text": "API key\n\n\n\nSign up at https://www.perplexity.ai to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatPerplexity requires the openai package (e.g., pip install openai).", + "text": "Name\nType\nDescription\n\n\n\n\n\nlist[TokenUsage] | None\nA list of dictionaries with the following keys: “name”, “input”, and “output”. If no tokens have been logged, then None is returned.", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "Query token usage", + "token_usage" ] }, { - "objectID": "reference/ChatPerplexity.html#examples", - "href": "reference/ChatPerplexity.html#examples", - "title": "ChatPerplexity", + "objectID": "reference/types.Content.html", + "href": "reference/types.Content.html", + "title": "types.Content", "section": "", - "text": "import os\nfrom chatlas import ChatPerplexity\n\nchat = ChatPerplexity(api_key=os.getenv(\"PERPLEXITY_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", + "text": "types.Content\ntypes.Content()\nBase class for all content types that can be appear in a Turn", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "User-facing types", + "types.Content" ] }, { - "objectID": "reference/ChatPerplexity.html#parameters", - "href": "reference/ChatPerplexity.html#parameters", - "title": "ChatPerplexity", + "objectID": "reference/image_url.html", + "href": "reference/image_url.html", + "title": "content_image_url", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the PERPLEXITY_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Perplexity’s API.\n'https://api.perplexity.ai/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", - "crumbs": [ - "Reference", - "Chat model providers", - "ChatPerplexity" - ] + "text": "content_image_url(url, detail='auto')\nEncode image content from a URL for chat input.\nThis function is used to prepare image URLs for input to the chatbot. It can handle both regular URLs and data URLs.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid." }, { - "objectID": "reference/ChatPerplexity.html#returns", - "href": "reference/ChatPerplexity.html#returns", - "title": "ChatPerplexity", + "objectID": "reference/image_url.html#parameters", + "href": "reference/image_url.html#parameters", + "title": "content_image_url", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'" + }, + { + "objectID": "reference/image_url.html#returns", + "href": "reference/image_url.html#returns", + "title": "content_image_url", + "section": "", + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." + }, + { + "objectID": "reference/image_url.html#examples", + "href": "reference/image_url.html#examples", + "title": "content_image_url", + "section": "", + "text": "from chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)" + }, + { + "objectID": "reference/image_url.html#raises", + "href": "reference/image_url.html#raises", + "title": "content_image_url", + "section": "", + "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid." + }, + { + "objectID": "reference/index.html", + "href": "reference/index.html", + "title": "Function reference", + "section": "", + "text": "Start a chat with a particular large language model (llm) provider.\n\n\n\nChatAnthropic\nChat with an Anthropic Claude model.\n\n\nChatAzureOpenAI\nChat with a model hosted on Azure OpenAI.\n\n\nChatBedrockAnthropic\nChat with an AWS bedrock model.\n\n\nChatGithub\nChat with a model hosted on the GitHub model marketplace.\n\n\nChatGoogle\nChat with a Google Gemini model.\n\n\nChatGroq\nChat with a model hosted on Groq.\n\n\nChatOllama\nChat with a local Ollama model.\n\n\nChatOpenAI\nChat with an OpenAI model.\n\n\nChatPerplexity\nChat with a model hosted on perplexity.ai.\n\n\n\n\n\n\nMethods and attributes available on a chat instance\n\n\n\nChat\nA chat object that can be used to interact with a language model.\n\n\n\n\n\n\nSubmit image input to the chat\n\n\n\ncontent_image_file\nEncode image content from a file for chat input.\n\n\ncontent_image_plot\nEncode the current matplotlib plot as an image for chat input.\n\n\ncontent_image_url\nEncode image content from a URL for chat input.\n\n\n\n\n\n\nInterpolate variables into prompt templates\n\n\n\ninterpolate\nInterpolate variables into a prompt\n\n\ninterpolate_file\nInterpolate variables into a prompt from a file\n\n\n\n\n\n\nAdd context to python function before registering it as a tool.\n\n\n\nTool\nDefine a tool\n\n\n\n\n\n\nA provider-agnostic representation of content generated during an assistant/user turn.\n\n\n\nTurn\nA user or assistant turn\n\n\n\n\n\n\n\n\n\ntoken_usage\nReport on token usage in the current session\n\n\n\n\n\n\n\n\n\nProvider\nA model provider interface for a Chat.\n\n\n\n\n\n\n\n\n\ntypes.Content\nBase class for all content types that can be appear in a Turn\n\n\ntypes.ContentImage\nBase class for image content.\n\n\ntypes.ContentImageInline\nInline image content.\n\n\ntypes.ContentImageRemote\nImage content from a URL.\n\n\ntypes.ContentJson\nJSON content\n\n\ntypes.ContentText\nText content for a Turn\n\n\ntypes.ContentToolRequest\nA request to call a tool/function\n\n\ntypes.ContentToolResult\nThe result of calling a tool/function\n\n\ntypes.ChatResponse\nChat response object.\n\n\ntypes.ChatResponseAsync\nChat response (async) object.\n\n\ntypes.ImageContentTypes\nAllowable content types for images.\n\n\ntypes.MISSING_TYPE\nA singleton representing a missing value.\n\n\ntypes.MISSING\n\n\n\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat()\n\n\ntypes.TokenUsage\nToken usage for a given provider (name).", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "Function reference" ] }, { - "objectID": "reference/ChatPerplexity.html#note", - "href": "reference/ChatPerplexity.html#note", - "title": "ChatPerplexity", + "objectID": "reference/index.html#chat-model-providers", + "href": "reference/index.html#chat-model-providers", + "title": "Function reference", "section": "", - "text": "This function is a lightweight wrapper around chatlas.ChatOpenAI with the defaults tweaked for perplexity.ai.", + "text": "Start a chat with a particular large language model (llm) provider.\n\n\n\nChatAnthropic\nChat with an Anthropic Claude model.\n\n\nChatAzureOpenAI\nChat with a model hosted on Azure OpenAI.\n\n\nChatBedrockAnthropic\nChat with an AWS bedrock model.\n\n\nChatGithub\nChat with a model hosted on the GitHub model marketplace.\n\n\nChatGoogle\nChat with a Google Gemini model.\n\n\nChatGroq\nChat with a model hosted on Groq.\n\n\nChatOllama\nChat with a local Ollama model.\n\n\nChatOpenAI\nChat with an OpenAI model.\n\n\nChatPerplexity\nChat with a model hosted on perplexity.ai.", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "Function reference" ] }, { - "objectID": "reference/ChatPerplexity.html#note-1", - "href": "reference/ChatPerplexity.html#note-1", - "title": "ChatPerplexity", + "objectID": "reference/index.html#the-chat-object", + "href": "reference/index.html#the-chat-object", + "title": "Function reference", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatPerplexity(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nPERPLEXITY_API_KEY=...\nfrom chatlas import ChatPerplexity\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatPerplexity()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport PERPLEXITY_API_KEY=...", + "text": "Methods and attributes available on a chat instance\n\n\n\nChat\nA chat object that can be used to interact with a language model.", "crumbs": [ "Reference", - "Chat model providers", - "ChatPerplexity" + "Function reference" ] }, { - "objectID": "reference/types.MISSING_TYPE.html", - "href": "reference/types.MISSING_TYPE.html", - "title": "types.MISSING_TYPE", + "objectID": "reference/index.html#image-input", + "href": "reference/index.html#image-input", + "title": "Function reference", "section": "", - "text": "types.MISSING_TYPE\ntypes.MISSING_TYPE()\nA singleton representing a missing value.", + "text": "Submit image input to the chat\n\n\n\ncontent_image_file\nEncode image content from a file for chat input.\n\n\ncontent_image_plot\nEncode the current matplotlib plot as an image for chat input.\n\n\ncontent_image_url\nEncode image content from a URL for chat input.", "crumbs": [ "Reference", - "User-facing types", - "types.MISSING_TYPE" + "Function reference" ] }, { - "objectID": "reference/image_file.html", - "href": "reference/image_file.html", - "title": "content_image_file", + "objectID": "reference/index.html#prompt-interpolation", + "href": "reference/index.html#prompt-interpolation", + "title": "Function reference", "section": "", - "text": "content_image_file(path, content_type='auto', resize='low')\nEncode image content from a file for chat input.\nThis function is used to prepare image files for input to the chatbot. It can handle various image formats and provides options for resizing.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[str, Literal['none', 'low', 'high']]\nResizing option for the image. Can be: - \"none\": No resizing - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\n'low'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid." + "text": "Interpolate variables into prompt templates\n\n\n\ninterpolate\nInterpolate variables into a prompt\n\n\ninterpolate_file\nInterpolate variables into a prompt from a file", + "crumbs": [ + "Reference", + "Function reference" + ] }, { - "objectID": "reference/image_file.html#parameters", - "href": "reference/image_file.html#parameters", - "title": "content_image_file", + "objectID": "reference/index.html#tool-calling", + "href": "reference/index.html#tool-calling", + "title": "Function reference", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[str, Literal['none', 'low', 'high']]\nResizing option for the image. Can be: - \"none\": No resizing - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\n'low'" + "text": "Add context to python function before registering it as a tool.\n\n\n\nTool\nDefine a tool", + "crumbs": [ + "Reference", + "Function reference" + ] }, { - "objectID": "reference/image_file.html#returns", - "href": "reference/image_file.html#returns", - "title": "content_image_file", + "objectID": "reference/index.html#turns", + "href": "reference/index.html#turns", + "title": "Function reference", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." + "text": "A provider-agnostic representation of content generated during an assistant/user turn.\n\n\n\nTurn\nA user or assistant turn", + "crumbs": [ + "Reference", + "Function reference" + ] }, { - "objectID": "reference/image_file.html#examples", - "href": "reference/image_file.html#examples", - "title": "content_image_file", + "objectID": "reference/index.html#query-token-usage", + "href": "reference/index.html#query-token-usage", + "title": "Function reference", "section": "", - "text": "from chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)" + "text": "token_usage\nReport on token usage in the current session", + "crumbs": [ + "Reference", + "Function reference" + ] }, { - "objectID": "reference/image_file.html#raises", - "href": "reference/image_file.html#raises", - "title": "content_image_file", + "objectID": "reference/index.html#implement-a-model-provider", + "href": "reference/index.html#implement-a-model-provider", + "title": "Function reference", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid." + "text": "Provider\nA model provider interface for a Chat.", + "crumbs": [ + "Reference", + "Function reference" + ] }, { - "objectID": "reference/ChatBedrockAnthropic.html", - "href": "reference/ChatBedrockAnthropic.html", - "title": "ChatBedrockAnthropic", + "objectID": "reference/index.html#user-facing-types", + "href": "reference/index.html#user-facing-types", + "title": "Function reference", "section": "", - "text": "ChatBedrockAnthropic(\n model=None,\n max_tokens=4096,\n aws_secret_key=None,\n aws_access_key=None,\n aws_region=None,\n aws_profile=None,\n aws_session_token=None,\n base_url=None,\n system_prompt=None,\n turns=None,\n kwargs=None,\n)\nChat with an AWS bedrock model.\nAWS Bedrock provides a number of chat based models, including those Anthropic’s Claude.\n\n\n\n\n\n\n\n\nAWS credentials\n\n\n\nConsider using the approach outlined in this guide to manage your AWS credentials: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatBedrockAnthropic, requires the anthropic package with the bedrock extras (e.g., pip install anthropic[bedrock]).\n\n\n\n\n\nfrom chatlas import ChatBedrockAnthropic\n\nchat = ChatBedrockAnthropic(\n aws_profile=\"...\",\n aws_region=\"us-east\",\n aws_secret_key=\"...\",\n aws_access_key=\"...\",\n aws_session_token=\"...\",\n)\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\naws_secret_key\nOptional[str]\nThe AWS secret key to use for authentication.\nNone\n\n\naws_access_key\nOptional[str]\nThe AWS access key to use for authentication.\nNone\n\n\naws_region\nOptional[str]\nThe AWS region to use. Defaults to the AWS_REGION environment variable. If that is not set, defaults to 'us-east-1'.\nNone\n\n\naws_profile\nOptional[str]\nThe AWS profile to use.\nNone\n\n\naws_session_token\nOptional[str]\nThe AWS session token to use.\nNone\n\n\nbase_url\nOptional[str]\nThe base URL to use. Defaults to the ANTHROPIC_BEDROCK_BASE_URL environment variable. If that is not set, defaults to f\"https://bedrock-runtime.{aws_region}.amazonaws.com\".\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nkwargs\nOptional['ChatBedrockClientArgs']\nAdditional arguments to pass to the anthropic.AnthropicBedrock() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "types.Content\nBase class for all content types that can be appear in a Turn\n\n\ntypes.ContentImage\nBase class for image content.\n\n\ntypes.ContentImageInline\nInline image content.\n\n\ntypes.ContentImageRemote\nImage content from a URL.\n\n\ntypes.ContentJson\nJSON content\n\n\ntypes.ContentText\nText content for a Turn\n\n\ntypes.ContentToolRequest\nA request to call a tool/function\n\n\ntypes.ContentToolResult\nThe result of calling a tool/function\n\n\ntypes.ChatResponse\nChat response object.\n\n\ntypes.ChatResponseAsync\nChat response (async) object.\n\n\ntypes.ImageContentTypes\nAllowable content types for images.\n\n\ntypes.MISSING_TYPE\nA singleton representing a missing value.\n\n\ntypes.MISSING\n\n\n\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat()\n\n\ntypes.TokenUsage\nToken usage for a given provider (name).", "crumbs": [ "Reference", - "Chat model providers", - "ChatBedrockAnthropic" + "Function reference" ] }, { - "objectID": "reference/ChatBedrockAnthropic.html#prerequisites", - "href": "reference/ChatBedrockAnthropic.html#prerequisites", - "title": "ChatBedrockAnthropic", + "objectID": "reference/types.ContentToolResult.html", + "href": "reference/types.ContentToolResult.html", + "title": "types.ContentToolResult", "section": "", - "text": "AWS credentials\n\n\n\nConsider using the approach outlined in this guide to manage your AWS credentials: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatBedrockAnthropic, requires the anthropic package with the bedrock extras (e.g., pip install anthropic[bedrock]).", + "text": "types.ContentToolResult(self, id, value=None, error=None)\nThe result of calling a tool/function\nThis content type isn’t meant to be used directly. Instead, it’s automatically generated by Chat when a tool/function is called (in response to a ContentToolRequest).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nThe unique identifier of the tool request.\nrequired\n\n\nvalue\nAny\nThe value returned by the tool/function.\nNone\n\n\nerror\nOptional[str]\nAn error message if the tool/function call failed.\nNone", "crumbs": [ "Reference", - "Chat model providers", - "ChatBedrockAnthropic" + "User-facing types", + "types.ContentToolResult" ] }, { - "objectID": "reference/ChatBedrockAnthropic.html#examples", - "href": "reference/ChatBedrockAnthropic.html#examples", - "title": "ChatBedrockAnthropic", + "objectID": "reference/types.ContentToolResult.html#parameters", + "href": "reference/types.ContentToolResult.html#parameters", + "title": "types.ContentToolResult", "section": "", - "text": "from chatlas import ChatBedrockAnthropic\n\nchat = ChatBedrockAnthropic(\n aws_profile=\"...\",\n aws_region=\"us-east\",\n aws_secret_key=\"...\",\n aws_access_key=\"...\",\n aws_session_token=\"...\",\n)\nchat.chat(\"What is the capital of France?\")", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nThe unique identifier of the tool request.\nrequired\n\n\nvalue\nAny\nThe value returned by the tool/function.\nNone\n\n\nerror\nOptional[str]\nAn error message if the tool/function call failed.\nNone", "crumbs": [ "Reference", - "Chat model providers", - "ChatBedrockAnthropic" + "User-facing types", + "types.ContentToolResult" ] }, { - "objectID": "reference/ChatBedrockAnthropic.html#parameters", - "href": "reference/ChatBedrockAnthropic.html#parameters", - "title": "ChatBedrockAnthropic", + "objectID": "reference/ChatGroq.html", + "href": "reference/ChatGroq.html", + "title": "ChatGroq", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\naws_secret_key\nOptional[str]\nThe AWS secret key to use for authentication.\nNone\n\n\naws_access_key\nOptional[str]\nThe AWS access key to use for authentication.\nNone\n\n\naws_region\nOptional[str]\nThe AWS region to use. Defaults to the AWS_REGION environment variable. If that is not set, defaults to 'us-east-1'.\nNone\n\n\naws_profile\nOptional[str]\nThe AWS profile to use.\nNone\n\n\naws_session_token\nOptional[str]\nThe AWS session token to use.\nNone\n\n\nbase_url\nOptional[str]\nThe base URL to use. Defaults to the ANTHROPIC_BEDROCK_BASE_URL environment variable. If that is not set, defaults to f\"https://bedrock-runtime.{aws_region}.amazonaws.com\".\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nkwargs\nOptional['ChatBedrockClientArgs']\nAdditional arguments to pass to the anthropic.AnthropicBedrock() client constructor.\nNone", + "text": "ChatGroq(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.groq.com/openai/v1',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on Groq.\nGroq provides a platform for highly efficient AI inference.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://groq.com to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGroq requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGroq\n\nchat = ChatGroq(api_key=os.getenv(\"GROQ_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GROQ_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Groq’s API.\n'https://api.groq.com/openai/v1'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for groq.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGroq(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGROQ_API_KEY=...\nfrom chatlas import ChatGroq\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGroq()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GROQ_API_KEY=...", "crumbs": [ "Reference", "Chat model providers", - "ChatBedrockAnthropic" + "ChatGroq" ] }, { - "objectID": "reference/ChatBedrockAnthropic.html#returns", - "href": "reference/ChatBedrockAnthropic.html#returns", - "title": "ChatBedrockAnthropic", + "objectID": "reference/ChatGroq.html#prerequisites", + "href": "reference/ChatGroq.html#prerequisites", + "title": "ChatGroq", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "API key\n\n\n\nSign up at https://groq.com to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGroq requires the openai package (e.g., pip install openai).", "crumbs": [ "Reference", "Chat model providers", - "ChatBedrockAnthropic" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html", - "href": "reference/ChatOpenAI.html", - "title": "ChatOpenAI", + "objectID": "reference/ChatGroq.html#examples", + "href": "reference/ChatGroq.html#examples", + "title": "ChatGroq", "section": "", - "text": "ChatOpenAI(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.openai.com/v1',\n seed=MISSING,\n kwargs=None,\n)\nChat with an OpenAI model.\nOpenAI provides a number of chat based models under the ChatGPT moniker.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nNote that a ChatGPT Plus membership does not give you the ability to call models via the API. You will need to go to the developer platform to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatOpenAI requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ChatModel | str]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the OPENAI_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses OpenAI.\n'https://api.openai.com/v1'\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nPasting an API key into a chat constructor (e.g., ChatOpenAI(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nOPENAI_API_KEY=...\nfrom chatlas import ChatOpenAI\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatOpenAI()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport OPENAI_API_KEY=...", + "text": "import os\nfrom chatlas import ChatGroq\n\nchat = ChatGroq(api_key=os.getenv(\"GROQ_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", "Chat model providers", - "ChatOpenAI" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html#prerequisites", - "href": "reference/ChatOpenAI.html#prerequisites", - "title": "ChatOpenAI", + "objectID": "reference/ChatGroq.html#parameters", + "href": "reference/ChatGroq.html#parameters", + "title": "ChatGroq", "section": "", - "text": "API key\n\n\n\nNote that a ChatGPT Plus membership does not give you the ability to call models via the API. You will need to go to the developer platform to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatOpenAI requires the openai package (e.g., pip install openai).", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GROQ_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Groq’s API.\n'https://api.groq.com/openai/v1'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", "crumbs": [ "Reference", "Chat model providers", - "ChatOpenAI" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html#examples", - "href": "reference/ChatOpenAI.html#examples", - "title": "ChatOpenAI", + "objectID": "reference/ChatGroq.html#returns", + "href": "reference/ChatGroq.html#returns", + "title": "ChatGroq", "section": "", - "text": "import os\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", "crumbs": [ "Reference", "Chat model providers", - "ChatOpenAI" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html#parameters", - "href": "reference/ChatOpenAI.html#parameters", - "title": "ChatOpenAI", + "objectID": "reference/ChatGroq.html#note", + "href": "reference/ChatGroq.html#note", + "title": "ChatGroq", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ChatModel | str]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the OPENAI_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses OpenAI.\n'https://api.openai.com/v1'\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", + "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for groq.", "crumbs": [ "Reference", "Chat model providers", - "ChatOpenAI" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html#returns", - "href": "reference/ChatOpenAI.html#returns", - "title": "ChatOpenAI", + "objectID": "reference/ChatGroq.html#note-1", + "href": "reference/ChatGroq.html#note-1", + "title": "ChatGroq", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", + "text": "Pasting an API key into a chat constructor (e.g., ChatGroq(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGROQ_API_KEY=...\nfrom chatlas import ChatGroq\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGroq()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GROQ_API_KEY=...", "crumbs": [ "Reference", "Chat model providers", - "ChatOpenAI" + "ChatGroq" ] }, { - "objectID": "reference/ChatOpenAI.html#note", - "href": "reference/ChatOpenAI.html#note", - "title": "ChatOpenAI", + "objectID": "reference/types.ContentImageRemote.html", + "href": "reference/types.ContentImageRemote.html", + "title": "types.ContentImageRemote", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatOpenAI(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nOPENAI_API_KEY=...\nfrom chatlas import ChatOpenAI\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatOpenAI()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport OPENAI_API_KEY=...", + "text": "types.ContentImageRemote(self, url, detail='auto')\nImage content from a URL.\nThis is the return type for content_image_url. It’s not meant to be used directly.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nA detail setting for the image. Can be \"auto\", \"low\", or \"high\".\n'auto'", "crumbs": [ "Reference", - "Chat model providers", - "ChatOpenAI" + "User-facing types", + "types.ContentImageRemote" ] }, { - "objectID": "reference/content_image_file.html", - "href": "reference/content_image_file.html", - "title": "content_image_file", + "objectID": "reference/types.ContentImageRemote.html#parameters", + "href": "reference/types.ContentImageRemote.html#parameters", + "title": "types.ContentImageRemote", "section": "", - "text": "content_image_file(path, content_type='auto', resize=MISSING)\nEncode image content from a file for chat input.\nThis function is used to prepare image files for input to the chatbot. It can handle various image formats and provides options for resizing.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[Literal['low', 'high', 'none'], str, MISSING_TYPE]\nResizing option for the image. Can be: - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - \"none\": No resizing - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\nMISSING\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nA detail setting for the image. Can be \"auto\", \"low\", or \"high\".\n'auto'", "crumbs": [ "Reference", - "Image input", - "content_image_file" + "User-facing types", + "types.ContentImageRemote" ] }, { - "objectID": "reference/content_image_file.html#parameters", - "href": "reference/content_image_file.html#parameters", - "title": "content_image_file", + "objectID": "reference/types.MISSING.html", + "href": "reference/types.MISSING.html", + "title": "types.MISSING", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[Literal['low', 'high', 'none'], str, MISSING_TYPE]\nResizing option for the image. Can be: - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - \"none\": No resizing - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\nMISSING", + "text": "types.MISSING\ntypes.MISSING", "crumbs": [ "Reference", - "Image input", - "content_image_file" + "User-facing types", + "types.MISSING" ] }, { - "objectID": "reference/content_image_file.html#returns", - "href": "reference/content_image_file.html#returns", - "title": "content_image_file", + "objectID": "reference/types.ContentText.html", + "href": "reference/types.ContentText.html", + "title": "types.ContentText", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", + "text": "types.ContentText\ntypes.ContentText(self, text)\nText content for a Turn", "crumbs": [ "Reference", - "Image input", - "content_image_file" + "User-facing types", + "types.ContentText" ] }, { - "objectID": "reference/content_image_file.html#examples", - "href": "reference/content_image_file.html#examples", - "title": "content_image_file", + "objectID": "reference/types.ContentToolRequest.html", + "href": "reference/types.ContentToolRequest.html", + "title": "types.ContentToolRequest", "section": "", - "text": "from chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)", + "text": "types.ContentToolRequest(self, id, name, arguments)\nA request to call a tool/function\nThis content type isn’t meant to be used directly. Instead, it’s automatically generated by Chat when a tool/function is requested by the model assistant.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nA unique identifier for this request.\nrequired\n\n\nname\nstr\nThe name of the tool/function to call.\nrequired\n\n\narguments\nobject\nThe arguments to pass to the tool/function.\nrequired", "crumbs": [ "Reference", - "Image input", - "content_image_file" + "User-facing types", + "types.ContentToolRequest" ] }, { - "objectID": "reference/content_image_file.html#raises", - "href": "reference/content_image_file.html#raises", - "title": "content_image_file", + "objectID": "reference/types.ContentToolRequest.html#parameters", + "href": "reference/types.ContentToolRequest.html#parameters", + "title": "types.ContentToolRequest", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nA unique identifier for this request.\nrequired\n\n\nname\nstr\nThe name of the tool/function to call.\nrequired\n\n\narguments\nobject\nThe arguments to pass to the tool/function.\nrequired", "crumbs": [ "Reference", - "Image input", - "content_image_file" + "User-facing types", + "types.ContentToolRequest" ] }, { - "objectID": "reference/ChatAnthropic.html", - "href": "reference/ChatAnthropic.html", - "title": "ChatAnthropic", + "objectID": "reference/content_image_plot.html", + "href": "reference/content_image_plot.html", + "title": "content_image_plot", "section": "", - "text": "ChatAnthropic(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n max_tokens=4096,\n kwargs=None,\n)\nChat with an Anthropic Claude model.\nAnthropic provides a number of chat based models under the Claude moniker.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nNote that a Claude Prop membership does not give you the ability to call models via the API. You will need to go to the developer console to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAnthropic requires the anthropic package (e.g., pip install anthropic).\n\n\n\n\n\nimport os\nfrom chatlas import ChatAnthropic\n\nchat = ChatAnthropic(api_key=os.getenv(\"ANTHROPIC_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ModelParam]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the ANTHROPIC_API_KEY environment variable.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the anthropic.Anthropic() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.\n\n\n\n\n\n\nPasting an API key into a chat constructor (e.g., ChatAnthropic(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nANTHROPIC_API_KEY=...\nfrom chatlas import ChatAnthropic\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatAnthropic()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport ANTHROPIC_API_KEY=...", + "text": "content_image_plot(width=768, height=768, dpi=72)\nEncode the current matplotlib plot as an image for chat input.\nThis function captures the current matplotlib plot, resizes it to the specified dimensions, and prepares it for chat input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Image input", + "content_image_plot" ] }, { - "objectID": "reference/ChatAnthropic.html#prerequisites", - "href": "reference/ChatAnthropic.html#prerequisites", - "title": "ChatAnthropic", + "objectID": "reference/content_image_plot.html#parameters", + "href": "reference/content_image_plot.html#parameters", + "title": "content_image_plot", "section": "", - "text": "API key\n\n\n\nNote that a Claude Prop membership does not give you the ability to call models via the API. You will need to go to the developer console to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAnthropic requires the anthropic package (e.g., pip install anthropic).", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Image input", + "content_image_plot" ] }, { - "objectID": "reference/ChatAnthropic.html#examples", - "href": "reference/ChatAnthropic.html#examples", - "title": "ChatAnthropic", + "objectID": "reference/content_image_plot.html#returns", + "href": "reference/content_image_plot.html#returns", + "title": "content_image_plot", "section": "", - "text": "import os\nfrom chatlas import ChatAnthropic\n\nchat = ChatAnthropic(api_key=os.getenv(\"ANTHROPIC_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Image input", + "content_image_plot" ] }, { - "objectID": "reference/ChatAnthropic.html#parameters", - "href": "reference/ChatAnthropic.html#parameters", - "title": "ChatAnthropic", + "objectID": "reference/content_image_plot.html#raises", + "href": "reference/content_image_plot.html#raises", + "title": "content_image_plot", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ModelParam]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the ANTHROPIC_API_KEY environment variable.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the anthropic.Anthropic() client constructor.\nNone", + "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Image input", + "content_image_plot" ] }, { - "objectID": "reference/ChatAnthropic.html#returns", - "href": "reference/ChatAnthropic.html#returns", - "title": "ChatAnthropic", + "objectID": "reference/content_image_plot.html#examples", + "href": "reference/content_image_plot.html#examples", + "title": "content_image_plot", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "from chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Image input", + "content_image_plot" ] }, { - "objectID": "reference/ChatAnthropic.html#note", - "href": "reference/ChatAnthropic.html#note", - "title": "ChatAnthropic", + "objectID": "reference/Turn.html", + "href": "reference/Turn.html", + "title": "Turn", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatAnthropic(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nANTHROPIC_API_KEY=...\nfrom chatlas import ChatAnthropic\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatAnthropic()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport ANTHROPIC_API_KEY=...", + "text": "Turn(self, role, contents, *, tokens=None, finish_reason=None, completion=None)\nA user or assistant turn\nEvery conversation with a chatbot consists of pairs of user and assistant turns, corresponding to an HTTP request and response. These turns are represented by the Turn object, which contains a list of Contents representing the individual messages within the turn. These might be text, images, tool requests (assistant only), or tool responses (user only).\nNote that a call to .chat() and related functions may result in multiple user-assistant turn cycles. For example, if you have registered tools, chatlas will automatically handle the tool calling loop, which may result in any number of additional cycles.\n\n\nfrom chatlas import Turn, ChatOpenAI, ChatAnthropic\n\nchat = ChatOpenAI()\nstr(chat.chat(\"What is the capital of France?\"))\nturns = chat.get_turns()\nassert len(turns) == 2\nassert isinstance(turns[0], Turn)\nassert turns[0].role == \"user\"\nassert turns[1].role == \"assistant\"\n\n# Load context into a new chat instance\nchat2 = ChatAnthropic(turns=turns)\nturns2 = chat2.get_turns()\nassert turns == turns2\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['user', 'assistant', 'system']\nEither “user”, “assistant”, or “system”.\nrequired\n\n\ncontents\nstr | Sequence[Content | str]\nA list of Content objects.\nrequired\n\n\ntokens\nOptional[tuple[int, int]]\nA numeric vector of length 2 representing the number of input and output tokens (respectively) used in this turn. Currently only recorded for assistant turns.\nNone\n\n\nfinish_reason\nOptional[str]\nA string indicating the reason why the conversation ended. This is only relevant for assistant turns.\nNone\n\n\ncompletion\nOptional[CompletionT]\nThe completion object returned by the provider. This is useful if there’s information returned by the provider that chatlas doesn’t otherwise expose. This is only relevant for assistant turns.\nNone", "crumbs": [ "Reference", - "Chat model providers", - "ChatAnthropic" + "Turns", + "Turn" ] }, { - "objectID": "reference/interpolate_file.html", - "href": "reference/interpolate_file.html", - "title": "interpolate_file", + "objectID": "reference/Turn.html#examples", + "href": "reference/Turn.html#examples", + "title": "Turn", "section": "", - "text": "interpolate_file(\n path,\n *,\n variables=None,\n variable_start='{{',\n variable_end='}}',\n)\nInterpolate variables into a prompt from a file\nThis is a light-weight wrapper around the Jinja2 templating engine, making it easier to interpolate dynamic data into a static prompt. Compared to f-strings, which expects you to wrap dynamic values in { }, this function expects { } instead, making it easier to include Python code and JSON in your prompt.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nUnion[str, Path]\nThe path to the file containing the prompt to interpolate.\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.\n\n\n\n\n\n\ninterpolate Interpolating data into a system prompt", + "text": "from chatlas import Turn, ChatOpenAI, ChatAnthropic\n\nchat = ChatOpenAI()\nstr(chat.chat(\"What is the capital of France?\"))\nturns = chat.get_turns()\nassert len(turns) == 2\nassert isinstance(turns[0], Turn)\nassert turns[0].role == \"user\"\nassert turns[1].role == \"assistant\"\n\n# Load context into a new chat instance\nchat2 = ChatAnthropic(turns=turns)\nturns2 = chat2.get_turns()\nassert turns == turns2", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate_file" + "Turns", + "Turn" ] }, { - "objectID": "reference/interpolate_file.html#parameters", - "href": "reference/interpolate_file.html#parameters", - "title": "interpolate_file", + "objectID": "reference/Turn.html#parameters", + "href": "reference/Turn.html#parameters", + "title": "Turn", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nUnion[str, Path]\nThe path to the file containing the prompt to interpolate.\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['user', 'assistant', 'system']\nEither “user”, “assistant”, or “system”.\nrequired\n\n\ncontents\nstr | Sequence[Content | str]\nA list of Content objects.\nrequired\n\n\ntokens\nOptional[tuple[int, int]]\nA numeric vector of length 2 representing the number of input and output tokens (respectively) used in this turn. Currently only recorded for assistant turns.\nNone\n\n\nfinish_reason\nOptional[str]\nA string indicating the reason why the conversation ended. This is only relevant for assistant turns.\nNone\n\n\ncompletion\nOptional[CompletionT]\nThe completion object returned by the provider. This is useful if there’s information returned by the provider that chatlas doesn’t otherwise expose. This is only relevant for assistant turns.\nNone", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate_file" + "Turns", + "Turn" ] }, { - "objectID": "reference/interpolate_file.html#returns", - "href": "reference/interpolate_file.html#returns", - "title": "interpolate_file", + "objectID": "reference/ChatAzureOpenAI.html", + "href": "reference/ChatAzureOpenAI.html", + "title": "ChatAzureOpenAI", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.", + "text": "ChatAzureOpenAI(\n endpoint,\n deployment_id,\n api_version,\n api_key=None,\n system_prompt=None,\n turns=None,\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on Azure OpenAI.\nThe Azure OpenAI server hosts a number of open source models as well as proprietary models from OpenAI.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAzureOpenAI requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatAzureOpenAI\n\nchat = ChatAzureOpenAI(\n endpoint=os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n deployment_id=\"REPLACE_WITH_YOUR_DEPLOYMENT_ID\",\n api_version=\"YYYY-MM-DD\",\n api_key=os.getenv(\"AZURE_OPENAI_API_KEY\"),\n)\n\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nendpoint\nstr\nAzure OpenAI endpoint url with protocol and hostname, i.e. https://{your-resource-name}.openai.azure.com. Defaults to using the value of the AZURE_OPENAI_ENDPOINT envinronment variable.\nrequired\n\n\ndeployment_id\nstr\nDeployment id for the model you want to use.\nrequired\n\n\napi_version\nstr\nThe API version to use.\nrequired\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the AZURE_OPENAI_API_KEY environment variable.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatAzureClientArgs']\nAdditional arguments to pass to the openai.AzureOpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate_file" + "Chat model providers", + "ChatAzureOpenAI" ] }, { - "objectID": "reference/interpolate_file.html#see-also", - "href": "reference/interpolate_file.html#see-also", - "title": "interpolate_file", + "objectID": "reference/ChatAzureOpenAI.html#prerequisites", + "href": "reference/ChatAzureOpenAI.html#prerequisites", + "title": "ChatAzureOpenAI", "section": "", - "text": "interpolate Interpolating data into a system prompt", + "text": "Python requirements\n\n\n\nChatAzureOpenAI requires the openai package (e.g., pip install openai).", "crumbs": [ "Reference", - "Prompt interpolation", - "interpolate_file" + "Chat model providers", + "ChatAzureOpenAI" ] }, { - "objectID": "reference/Chat.html", - "href": "reference/Chat.html", - "title": "Chat", + "objectID": "reference/ChatAzureOpenAI.html#examples", + "href": "reference/ChatAzureOpenAI.html#examples", + "title": "ChatAzureOpenAI", "section": "", - "text": "Chat(self, provider, turns=None)\nA chat object that can be used to interact with a language model.\nA Chat is an sequence of sequence of user and assistant Turns sent to a specific Provider. A Chat takes care of managing the state associated with the chat; i.e. it records the messages that you send to the server, and the messages that you receive back. If you register a tool (i.e. an function that the assistant can call on your behalf), it also takes care of the tool loop.\nYou should generally not create this object yourself, but instead call ChatOpenAI or friends instead.\n\n\n\n\n\nName\nDescription\n\n\n\n\nsystem_prompt\nA property to get (or set) the system prompt for the chat.\n\n\n\n\n\n\n\n\n\nName\nDescription\n\n\n\n\napp\nEnter a web-based chat app to interact with the LLM.\n\n\nchat\nGenerate a response from the chat.\n\n\nchat_async\nGenerate a response from the chat asynchronously.\n\n\nconsole\nEnter a chat console to interact with the LLM.\n\n\nexport\nExport the chat history to a file.\n\n\nextract_data\nExtract structured data from the given input.\n\n\nextract_data_async\nExtract structured data from the given input asynchronously.\n\n\nget_last_turn\nGet the last turn in the chat with a specific role.\n\n\nget_turns\nGet all the turns (i.e., message contents) in the chat.\n\n\nregister_tool\nRegister a tool (function) with the chat.\n\n\nset_echo_options\nSet echo styling options for the chat.\n\n\nset_turns\nSet the turns of the chat.\n\n\nstream\nGenerate a response from the chat in a streaming fashion.\n\n\nstream_async\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\ntokens\nGet the tokens for each turn in the chat.\n\n\n\n\n\nChat.app(stream=True, port=0, launch_browser=True, bg_thread=None, kwargs=None)\nEnter a web-based chat app to interact with the LLM.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nport\nint\nThe port to run the app on (the default is 0, which will choose a random port).\n0\n\n\nlaunch_browser\nbool\nWhether to launch a browser window.\nTrue\n\n\nbg_thread\nOptional[bool]\nWhether to run the app in a background thread. If None, the app will run in a background thread if the current environment is a notebook.\nNone\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\nChat.chat(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.chat_async(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls, images, etc), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.console(echo='text', stream=True, kwargs=None)\nEnter a chat console to interact with the LLM.\nTo quit, input ‘exit’ or press Ctrl+C.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\nChat.export(\n filename,\n *,\n turns=None,\n title=None,\n include='text',\n include_system_prompt=True,\n overwrite=False,\n)\nExport the chat history to a file.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfilename\nstr | Path\nThe filename to export the chat to. Currently this must be a .md or .html file.\nrequired\n\n\nturns\nOptional[Sequence[Turn]]\nThe .get_turns() to export. If not provided, the chat’s current turns will be used.\nNone\n\n\ntitle\nOptional[str]\nA title to place at the top of the exported file.\nNone\n\n\noverwrite\nbool\nWhether to overwrite the file if it already exists.\nFalse\n\n\ninclude\nLiteral['text', 'all']\nWhether to include text content, all content (i.e., tool calls), or no content.\n'text'\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in a \nTrue\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nPath\nThe path to the exported file.\n\n\n\n\n\n\n\nChat.extract_data(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.extract_data_async(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks). Defaults to True if echo is not “none”.\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.get_last_turn(role='assistant')\nGet the last turn in the chat with a specific role.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['assistant', 'user', 'system']\nThe role of the turn to return.\n'assistant'\n\n\n\n\n\n\n\nChat.get_turns(include_system_prompt=False)\nGet all the turns (i.e., message contents) in the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in the turns.\nFalse\n\n\n\n\n\n\n\nChat.register_tool(func, *, model=None)\nRegister a tool (function) with the chat.\nThe function will always be invoked in the current Python process.\n\n\nIf your tool has straightforward input parameters, you can just register the function directly (type hints and a docstring explaning both what the function does and what the parameters are for is strongly recommended):\nfrom chatlas import ChatOpenAI, Tool\n\n\ndef add(a: int, b: int) -> int:\n '''\n Add two numbers together.\n\n#### Parameters {.doc-section .doc-section-----parameters}\n\n a : int\n The first number to add.\n b : int\n The second number to add.\n '''\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add)\nchat.chat(\"What is 2 + 2?\")\nIf your tool has more complex input parameters, you can provide a Pydantic model that corresponds to the input parameters for the function, This way, you can have fields that hold other model(s) (for more complex input parameters), and also more directly document the input parameters:\nfrom chatlas import ChatOpenAI, Tool\nfrom pydantic import BaseModel, Field\n\n\nclass AddParams(BaseModel):\n '''Add two numbers together.'''\n\n a: int = Field(description=\"The first number to add.\")\n\n b: int = Field(description=\"The second number to add.\")\n\n\ndef add(a: int, b: int) -> int:\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add, model=AddParams)\nchat.chat(\"What is 2 + 2?\")\n\n\n\n\n\nfunc The function to be invoked when the tool is called. model A Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\n\n\nChat.set_echo_options(rich_markdown=None, rich_console=None, css_styles=None)\nSet echo styling options for the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrich_markdown\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.markdown.Markdown(). This is only relevant when outputting to the console.\nNone\n\n\nrich_console\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.console.Console(). This is only relevant when outputting to the console.\nNone\n\n\ncss_styles\nOptional[dict[str, str]]\nA dictionary of CSS styles to apply to IPython.display.Markdown(). This is only relevant when outputing to the browser.\nNone\n\n\n\n\n\n\n\nChat.set_turns(turns)\nSet the turns of the chat.\nThis method is primarily useful for clearing or setting the turns of the chat (i.e., limiting the context window).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nturns\nSequence[Turn]\nThe turns to set. Turns with the role “system” are not allowed.\nrequired\n\n\n\n\n\n\n\nChat.stream(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.stream_async(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.tokens()\nGet the tokens for each turn in the chat.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[tuple[int, int] | None]\nA list of tuples, where each tuple contains the start and end token indices for a turn.", + "text": "import os\nfrom chatlas import ChatAzureOpenAI\n\nchat = ChatAzureOpenAI(\n endpoint=os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n deployment_id=\"REPLACE_WITH_YOUR_DEPLOYMENT_ID\",\n api_version=\"YYYY-MM-DD\",\n api_key=os.getenv(\"AZURE_OPENAI_API_KEY\"),\n)\n\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", - "The chat object", - "Chat" + "Chat model providers", + "ChatAzureOpenAI" ] }, { - "objectID": "reference/Chat.html#attributes", - "href": "reference/Chat.html#attributes", - "title": "Chat", + "objectID": "reference/ChatAzureOpenAI.html#parameters", + "href": "reference/ChatAzureOpenAI.html#parameters", + "title": "ChatAzureOpenAI", "section": "", - "text": "Name\nDescription\n\n\n\n\nsystem_prompt\nA property to get (or set) the system prompt for the chat.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nendpoint\nstr\nAzure OpenAI endpoint url with protocol and hostname, i.e. https://{your-resource-name}.openai.azure.com. Defaults to using the value of the AZURE_OPENAI_ENDPOINT envinronment variable.\nrequired\n\n\ndeployment_id\nstr\nDeployment id for the model you want to use.\nrequired\n\n\napi_version\nstr\nThe API version to use.\nrequired\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the AZURE_OPENAI_API_KEY environment variable.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatAzureClientArgs']\nAdditional arguments to pass to the openai.AzureOpenAI() client constructor.\nNone", "crumbs": [ "Reference", - "The chat object", - "Chat" + "Chat model providers", + "ChatAzureOpenAI" ] }, { - "objectID": "reference/Chat.html#methods", - "href": "reference/Chat.html#methods", - "title": "Chat", + "objectID": "reference/ChatAzureOpenAI.html#returns", + "href": "reference/ChatAzureOpenAI.html#returns", + "title": "ChatAzureOpenAI", "section": "", - "text": "Name\nDescription\n\n\n\n\napp\nEnter a web-based chat app to interact with the LLM.\n\n\nchat\nGenerate a response from the chat.\n\n\nchat_async\nGenerate a response from the chat asynchronously.\n\n\nconsole\nEnter a chat console to interact with the LLM.\n\n\nexport\nExport the chat history to a file.\n\n\nextract_data\nExtract structured data from the given input.\n\n\nextract_data_async\nExtract structured data from the given input asynchronously.\n\n\nget_last_turn\nGet the last turn in the chat with a specific role.\n\n\nget_turns\nGet all the turns (i.e., message contents) in the chat.\n\n\nregister_tool\nRegister a tool (function) with the chat.\n\n\nset_echo_options\nSet echo styling options for the chat.\n\n\nset_turns\nSet the turns of the chat.\n\n\nstream\nGenerate a response from the chat in a streaming fashion.\n\n\nstream_async\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\ntokens\nGet the tokens for each turn in the chat.\n\n\n\n\n\nChat.app(stream=True, port=0, launch_browser=True, bg_thread=None, kwargs=None)\nEnter a web-based chat app to interact with the LLM.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nport\nint\nThe port to run the app on (the default is 0, which will choose a random port).\n0\n\n\nlaunch_browser\nbool\nWhether to launch a browser window.\nTrue\n\n\nbg_thread\nOptional[bool]\nWhether to run the app in a background thread. If None, the app will run in a background thread if the current environment is a notebook.\nNone\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\nChat.chat(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.chat_async(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls, images, etc), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.console(echo='text', stream=True, kwargs=None)\nEnter a chat console to interact with the LLM.\nTo quit, input ‘exit’ or press Ctrl+C.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\nChat.export(\n filename,\n *,\n turns=None,\n title=None,\n include='text',\n include_system_prompt=True,\n overwrite=False,\n)\nExport the chat history to a file.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfilename\nstr | Path\nThe filename to export the chat to. Currently this must be a .md or .html file.\nrequired\n\n\nturns\nOptional[Sequence[Turn]]\nThe .get_turns() to export. If not provided, the chat’s current turns will be used.\nNone\n\n\ntitle\nOptional[str]\nA title to place at the top of the exported file.\nNone\n\n\noverwrite\nbool\nWhether to overwrite the file if it already exists.\nFalse\n\n\ninclude\nLiteral['text', 'all']\nWhether to include text content, all content (i.e., tool calls), or no content.\n'text'\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in a \nTrue\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nPath\nThe path to the exported file.\n\n\n\n\n\n\n\nChat.extract_data(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.extract_data_async(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks). Defaults to True if echo is not “none”.\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.get_last_turn(role='assistant')\nGet the last turn in the chat with a specific role.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['assistant', 'user', 'system']\nThe role of the turn to return.\n'assistant'\n\n\n\n\n\n\n\nChat.get_turns(include_system_prompt=False)\nGet all the turns (i.e., message contents) in the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in the turns.\nFalse\n\n\n\n\n\n\n\nChat.register_tool(func, *, model=None)\nRegister a tool (function) with the chat.\nThe function will always be invoked in the current Python process.\n\n\nIf your tool has straightforward input parameters, you can just register the function directly (type hints and a docstring explaning both what the function does and what the parameters are for is strongly recommended):\nfrom chatlas import ChatOpenAI, Tool\n\n\ndef add(a: int, b: int) -> int:\n '''\n Add two numbers together.\n\n#### Parameters {.doc-section .doc-section-----parameters}\n\n a : int\n The first number to add.\n b : int\n The second number to add.\n '''\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add)\nchat.chat(\"What is 2 + 2?\")\nIf your tool has more complex input parameters, you can provide a Pydantic model that corresponds to the input parameters for the function, This way, you can have fields that hold other model(s) (for more complex input parameters), and also more directly document the input parameters:\nfrom chatlas import ChatOpenAI, Tool\nfrom pydantic import BaseModel, Field\n\n\nclass AddParams(BaseModel):\n '''Add two numbers together.'''\n\n a: int = Field(description=\"The first number to add.\")\n\n b: int = Field(description=\"The second number to add.\")\n\n\ndef add(a: int, b: int) -> int:\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add, model=AddParams)\nchat.chat(\"What is 2 + 2?\")", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", - "The chat object", - "Chat" + "Chat model providers", + "ChatAzureOpenAI" ] }, { - "objectID": "reference/Chat.html#parameters-9", - "href": "reference/Chat.html#parameters-9", - "title": "Chat", + "objectID": "reference/ChatGithub.html", + "href": "reference/ChatGithub.html", + "title": "ChatGithub", "section": "", - "text": "func The function to be invoked when the tool is called. model A Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\n\n\nChat.set_echo_options(rich_markdown=None, rich_console=None, css_styles=None)\nSet echo styling options for the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrich_markdown\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.markdown.Markdown(). This is only relevant when outputting to the console.\nNone\n\n\nrich_console\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.console.Console(). This is only relevant when outputting to the console.\nNone\n\n\ncss_styles\nOptional[dict[str, str]]\nA dictionary of CSS styles to apply to IPython.display.Markdown(). This is only relevant when outputing to the browser.\nNone\n\n\n\n\n\n\n\nChat.set_turns(turns)\nSet the turns of the chat.\nThis method is primarily useful for clearing or setting the turns of the chat (i.e., limiting the context window).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nturns\nSequence[Turn]\nThe turns to set. Turns with the role “system” are not allowed.\nrequired\n\n\n\n\n\n\n\nChat.stream(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.stream_async(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.tokens()\nGet the tokens for each turn in the chat.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[tuple[int, int] | None]\nA list of tuples, where each tuple contains the start and end token indices for a turn.", + "text": "ChatGithub(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://models.inference.ai.azure.com/',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on the GitHub model marketplace.\nGitHub (via Azure) hosts a wide variety of open source models, some of which are fined tuned for specific tasks.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://github.com/marketplace/models to get an API key. You may need to apply for and be accepted into a beta access program.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGithub requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGithub\n\nchat = ChatGithub(api_key=os.getenv(\"GITHUB_PAT\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GITHUB_PAT environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Github’s API.\n'https://models.inference.ai.azure.com/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for the GitHub model marketplace.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGithub(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGITHUB_PAT=...\nfrom chatlas import ChatGithub\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGithub()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GITHUB_PAT=...", "crumbs": [ "Reference", - "The chat object", - "Chat" + "Chat model providers", + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html", - "href": "reference/ChatOllama.html", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#prerequisites", + "href": "reference/ChatGithub.html#prerequisites", + "title": "ChatGithub", "section": "", - "text": "ChatOllama(\n model=None,\n *,\n system_prompt=None,\n turns=None,\n base_url='http://localhost:11434',\n seed=None,\n kwargs=None,\n)\nChat with a local Ollama model.\nOllama makes it easy to run a wide-variety of open-source models locally, making it a great choice for privacy and security.\n\n\n\n\n\n\n\n\nOllama runtime\n\n\n\nChatOllama requires the ollama executable to be installed and running on your machine.\n\n\n\n\n\n\n\n\nPull model(s)\n\n\n\nOnce ollama is running locally, download a model from the command line (e.g. ollama pull llama3.2).\n\n\n\n\n\nfrom chatlas import ChatOllama\n\nchat = ChatOllama(model=\"llama3.2\")\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat. If None, a list of locally installed models will be printed.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses ollama’s API.\n'http://localhost:11434'\n\n\nseed\nOptional[int]\nOptional integer seed that helps to make output more reproducible.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for ollama.\n\n\n\nChatOllama currently doesn’t work with streaming tools, and tool calling more generally doesn’t seem to work very well with currently available models.", + "text": "API key\n\n\n\nSign up at https://github.com/marketplace/models to get an API key. You may need to apply for and be accepted into a beta access program.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGithub requires the openai package (e.g., pip install openai).", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html#prerequisites", - "href": "reference/ChatOllama.html#prerequisites", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#examples", + "href": "reference/ChatGithub.html#examples", + "title": "ChatGithub", "section": "", - "text": "Ollama runtime\n\n\n\nChatOllama requires the ollama executable to be installed and running on your machine.\n\n\n\n\n\n\n\n\nPull model(s)\n\n\n\nOnce ollama is running locally, download a model from the command line (e.g. ollama pull llama3.2).", + "text": "import os\nfrom chatlas import ChatGithub\n\nchat = ChatGithub(api_key=os.getenv(\"GITHUB_PAT\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html#examples", - "href": "reference/ChatOllama.html#examples", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#parameters", + "href": "reference/ChatGithub.html#parameters", + "title": "ChatGithub", "section": "", - "text": "from chatlas import ChatOllama\n\nchat = ChatOllama(model=\"llama3.2\")\nchat.chat(\"What is the capital of France?\")", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GITHUB_PAT environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Github’s API.\n'https://models.inference.ai.azure.com/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html#parameters", - "href": "reference/ChatOllama.html#parameters", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#returns", + "href": "reference/ChatGithub.html#returns", + "title": "ChatGithub", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat. If None, a list of locally installed models will be printed.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses ollama’s API.\n'http://localhost:11434'\n\n\nseed\nOptional[int]\nOptional integer seed that helps to make output more reproducible.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html#note", - "href": "reference/ChatOllama.html#note", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#note", + "href": "reference/ChatGithub.html#note", + "title": "ChatGithub", "section": "", - "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for ollama.", + "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for the GitHub model marketplace.", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "reference/ChatOllama.html#limitations", - "href": "reference/ChatOllama.html#limitations", - "title": "ChatOllama", + "objectID": "reference/ChatGithub.html#note-1", + "href": "reference/ChatGithub.html#note-1", + "title": "ChatGithub", "section": "", - "text": "ChatOllama currently doesn’t work with streaming tools, and tool calling more generally doesn’t seem to work very well with currently available models.", + "text": "Pasting an API key into a chat constructor (e.g., ChatGithub(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGITHUB_PAT=...\nfrom chatlas import ChatGithub\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGithub()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GITHUB_PAT=...", "crumbs": [ "Reference", "Chat model providers", - "ChatOllama" + "ChatGithub" ] }, { - "objectID": "web-apps.html", - "href": "web-apps.html", + "objectID": "get-started.html", + "href": "get-started.html", "title": "chatlas", "section": "", - "text": "In the intro, we learned how the .app() method launches a web app with a simple chat interface, for example:\nThis is a great way to quickly test your model, but you’ll likely want to embed similar functionality into a larger web app. Here’s how you can do that we different web frameworks." + "text": "chatlas makes it easy to access the wealth of large language models (LLMs) from Python. But what can you do with those models once you have access to them? This vignette will give you the basic vocabulary you need to use an LLM effectively and will show you some examples to ignite your creativity.\nIn this article we’ll mostly ignore how LLMs work, using them as convenient black boxes. If you want to get a sense of how they actually work, we recommend watching Jeremy Howard’s posit::conf(2023) keynote: A hacker’s guide to open source LLMs." }, { - "objectID": "web-apps.html#shiny", - "href": "web-apps.html#shiny", + "objectID": "get-started.html#vocabulary", + "href": "get-started.html#vocabulary", "title": "chatlas", - "section": "Shiny", - "text": "Shiny\nUsing Shiny’s ui.Chat component, you can simply pass user input from the component into the chat.stream() method. This generate a response stream that can then be passed to .append_message_stream().\nfrom chatlas import ChatAnthropic\nfrom shiny.express import ui\n\nchat_ui = ui.Chat(\n id=\"ui_chat\",\n messages=[\"Hi! How can I help you today?\"],\n)\nchat_ui.ui()\n\nchat = ChatAnthropic()\n\n@chat_ui.on_user_submit\nasync def _():\n response = chat.stream(chat_ui.user_input())\n await chat_ui.append_message_stream(response)" + "section": "Vocabulary", + "text": "Vocabulary\nWe’ll start by laying out the key vocab that you’ll need to understand LLMs. Unfortunately the vocab is all a little entangled: to understand one term you’ll often have to know a little about some of the others. So we’ll start with some simple definitions of the most important terms then iteratively go a little deeper.\nIt all starts with a prompt, which is the text (typically a question or a request) that you send to the LLM. This starts a conversation, a sequence of turns that alternate between user prompts and model responses. Inside the model, both the prompt and response are represented by a sequence of tokens, which represent either individual words or subcomponents of a word. The tokens are used to compute the cost of using a model and to measure the size of the context, the combination of the current prompt and any previous prompts and responses used to generate the next response.\nIt’s useful to make the distinction between providers and models. A provider is a web API that gives access to one or more models. The distinction is a bit subtle because providers are often synonymous with a model, like OpenAI and GPT, Anthropic and Claude, and Google and Gemini. But other providers, like Ollama, can host many different models, typically open source models like LLaMa and Mistral. Still other providers support both open and closed models, typically by partnering with a company that provides a popular closed model. For example, Azure OpenAI offers both open source models and OpenAI’s GPT, while AWS Bedrock offers both open source models and Anthropic’s Claude.\n\nWhat is a token?\nAn LLM is a model, and like all models needs some way to represent its inputs numerically. For LLMs, that means we need some way to convert words to numbers. This is the goal of the tokenizer. For example, using the GPT 4o tokenizer, the string “When was R created?” is converted to 5 tokens: 5958 (“When”), 673 (” was”), 460 (” R”), 5371 (” created”), 30 (“?”). As you can see, many simple strings can be represented by a single token. But more complex strings require multiple tokens. For example, the string “counterrevolutionary” requires 4 tokens: 32128 (“counter”), 264 (“re”), 9477 (“volution”), 815 (“ary”). (You can see how various strings are tokenized at http://tiktokenizer.vercel.app/).\nIt’s important to have a rough sense of how text is converted to tokens because tokens are used to determine the cost of a model and how much context can be used to predict the next response. On average an English word needs ~1.5 tokens so a page might require 375-400 tokens and a complete book might require 75,000 to 150,000 tokens. Other languages will typically require more tokens, because (in brief) LLMs are trained on data from the internet, which is primarily in English.\nLLMs are priced per million tokens. State of the art models (like GPT-4o or Claude 3.5 sonnet) cost $2-3 per million input tokens, and $10-15 per million output tokens. Cheaper models can cost much less, e.g. GPT-4o mini costs $0.15 per million input tokens and $0.60 per million output tokens. Even $10 of API credit will give you a lot of room for experimentation, particularly with cheaper models, and prices are likely to decline as model performance improves.\nTokens also used to measure the context window, which is how much text the LLM can use to generate the next response. As we’ll discuss shortly, the context length includes the full state of your conversation so far (both your prompts and the model’s responses), which means that cost grow rapidly with the number of conversational turns.\n\n\nWhat is a conversation?\nA conversation with an LLM takes place through a series of HTTP requests and responses: you send your question to the LLM as an HTTP request, and it sends back its reply as an HTTP response. In other words, a conversation consists of a sequence of a paired turns: a sent prompt and a returned response.\nIt’s important to note that a request includes not only the current user prompt, but every previous user prompt and model response. This means that:\n\nThe cost of a conversation grows quadratically with the number of turns: if you want to save money, keep your conversations short.\nEach response is affected by all previous prompts and responses. This can make a converstion get stuck in a local optimum, so it’s generally better to iterate by starting a new conversation with a better prompt rather than having a long back-and-forth.\nchatlas has full control over the conversational history. Because it’s chatlas’s responsibility to send the previous turns of the conversation, it’s possible to start a conversation with one model and finish it with another.\n\n\n\nWhat is a prompt?\nThe user prompt is the question that you send to the model. There are two other important prompts that underlie the user prompt:\n\nThe core system prompt, which is unchangeable, set by the model provider, and affects every conversation. You can see what these look like from Anthropic, who publishes their core system prompts.\nThe system prompt, which is set when you create a new conversation, and affects every response. It’s used to provide additional instructions to the model, shaping its responses to your needs. For example, you might use the system prompt to ask the model to always respond in Spanish or to write dependency-free base R code. You can also use the system prompt to provide the model with information it wouldn’t otherwise know, like the details of your database schema, or your preferred plotly theme and color palette.\n\nWhen you use a chat app like ChatGPT or claude.ai you can only iterate on the user prompt. But when you’re programming with LLMs, you’ll primarily iterate on the system prompt. For example, if you’re developing an app that helps a user write Python code, you’d work with the system prompt to ensure that user gets the style of code they want.\nWriting a good prompt, which is called prompt design, is key to effective use of LLMs. It is discussed in more detail in the prompt design article." }, { - "objectID": "web-apps.html#streamlit", - "href": "web-apps.html#streamlit", + "objectID": "get-started.html#example-uses", + "href": "get-started.html#example-uses", "title": "chatlas", - "section": "Streamlit", - "text": "Streamlit\nStreamlit is a popular Python library for building web apps. You can use the st.chat_input() and st.chat_message() methods to create a chat interface. Here’s an example of how you can use Chatlas with Streamlit:\nimport streamlit as st\nfrom chatlas import ChatOpenAI, Turn\n\nwith st.sidebar:\n openai_api_key = st.text_input(\n \"OpenAI API Key\", key=\"chatbot_api_key\", type=\"password\"\n )\n \"[Get an OpenAI API key](https://platform.openai.com/account/api-keys)\"\n \"[View the source code](https://github.com/streamlit/llm-examples/blob/main/Chatbot.py)\"\n\nst.title(\"💬 Chatbot\")\n\nif \"turns\" not in st.session_state:\n st.session_state[\"turns\"] = [\n Turn(role=\"assistant\", contents=\"How can I help you?\"),\n ]\n\nturns: list[Turn] = st.session_state.turns\n\nfor turn in turns:\n st.chat_message(turn.role).write(turn.text)\n\n\nif prompt := st.chat_input():\n if not openai_api_key:\n st.info(\"Please add your OpenAI API key to continue.\")\n st.stop()\n\n st.chat_message(\"user\").write(prompt)\n\n chat = ChatOpenAI(api_key=openai_api_key, turns=turns)\n response = chat.stream(prompt)\n\n with st.chat_message(\"assistant\"):\n st.write_stream(response)\n\n st.session_state[\"turns\"] = chat.get_turns()" + "section": "Example uses", + "text": "Example uses\nNow that you’ve got the basic vocab under your belt, I’m going to fire a bunch of interesting potential use cases at you. While there are special purpose tools that might solve these cases faster and/or cheaper, an LLM allows you to rapidly prototype a solution. This can be extremely valuable even if you end up using those more specialised tools in your final product.\nIn general, we recommend avoiding LLMs where accuracy is critical. That said, there are still many cases for their use. For example, even though they always requires some manual fiddling, you might save a bunch of time evern with an 80% correct solution. In fact, even a not-so-good solution can still be useful because it makes it easier to get started: it’s easier to react to something rather than to have to start from scratch with a blank page.\n\nChatbots\nA great place to start with chatlas and LLMs is to build a chatbot with a custom prompt. Chatbots are familiar interface and are easy to create via web application framework like Shiny or Streamlit. And there’s a surprising amount of value to creating a custom chatbot that has a prompt stuffed with useful knowledge. For example:\n\nHelp people use your new package. To do so, you need a custom prompt because LLMs were trained on data prior to your package’s existence. You can create a surprisingly useful tool just by preloading the prompt with your README and other documentation. This is how the chatlas assistant works.\nBuild language specific prompts for Python and/or R. Shiny assistant helps you build shiny apps (either in Python or R) by combining a prompt that gives general advice on building apps with a prompt for Python or R. The Python prompt is very detailed because there’s much less information about Shiny for Python in the existing LLM knowledgebases.\nHelp people find the answers to their questions. Even if you’ve written a bunch of documentation for something, you might find that you still get questions because folks can’t easily find exactly what they’re looking for. You can reduce the need to answer these questions by creating a chatbot with a prompt that contains your documentation. For example, if you’re a teacher, you could create a chatbot that includes your syllabus in the prompt. This eliminates a common class of question where the data necessary to answer the question is available, but hard to find.\n\nAnother direction is to give the chatbot additional context about your current environment. For example, aidea allows the user to interactively explore a dataset with the help of the LLM. It adds summary statistics about the dataset to the prompt so that the LLM knows something about your data. Along these lines, imagine writing a chatbot to help with data import that has a prompt which include all the files in the current directory along with their first few lines.\n\n\nStructured data extraction\nLLMs are often very good at extracting structured data from unstructured text. This can give you traction to analyse data that was previously unaccessible. For example:\n\nCustomer tickets and GitHub issues: you can use LLMs for quick and dirty sentiment analysis by extracting any specifically mentioned products and summarising the discussion as a few bullet points.\nGeocoding: LLMs do a surprisingly good job at geocoding, especially extracting addresses or finding the latitute/longitude of cities. There are specialised tools that do this better, but using an LLM makes it easy to get started.\nRecipes: I’ve extracted structured data from baking and cocktail recipes. Once you have the data in a structured form you can use your Python skills to better understand how recipes vary within a cookbook or to look for recipes that use the ingredients that you currently have in your kitchen. You could even use shiny assistant to help make those techniques available to anyone, not just Python users.\n\nStructured data extraction also work works well with images. It’s not the fastest or cheapest way to extract data but it makes it really easy to prototype ideas. For example, maybe you have a bunch of scanned documents that you want to index. You can convert PDFs to images (e.g. using something like pdf2image) then use structured data extraction to pull out key details.\nLearn more in the article on structured data extraction.\n\n\nProgramming\nLLMs can also be useful to solve general programming problems. For example:\n\nYou can use LLMs to explain code, or even ask them to generate a diagram.\nYou can ask an LLM to analyse your code for potential code smells or security issues. You can do this a function at a time, or explore including the entire source code for your package or script in the prompt.\nYou could automatically look up the documentation for an Python class/function, and include it in the prompt to make it easier to figure out how to use that class/function.\nI find it useful to have an LLM document a function for me, even knowing that it’s likely to be mostly incorrect. Having something to react to make it much easier for me to get started.\nIf you’re working with code or data from another programming language, you ask an LLM to convert it to Python code for you. Even if it’s not perfect, it’s still typically much faster than doing everything yourself.\nYou could use GitHub’s REST API to find unlabelled issues, extract the text, and ask the LLM to figure out what labels might be most appropriate. Or maybe an LLM might be able to help people create better reprexes, or simplify reprexes that are too complicated?\nWrite a detailed prompt that teaches the LLM about something it wouldn’t otherwise know about. For example, you might write a guide to updating code to use a new version of a package. If you have a programmable IDE, you could imagine being able to select code, transform it, and then replace the existing text. A real example of this is the R package pal, which includes prompts for updating source code to use the latest conventions in R for documentation, testing, error handling, and more." }, { - "objectID": "structured-data.html", - "href": "structured-data.html", - "title": "Structured data", + "objectID": "get-started.html#miscellaneous", + "href": "get-started.html#miscellaneous", + "title": "chatlas", + "section": "Miscellaneous", + "text": "Miscellaneous\nTo finish up here are a few other ideas that seem cool but didn’t seem to fit the above categories:\n\nAutomatically generate alt text for plots, using content_image_plot().\nAnalyse the text of your statistical report to look for flaws in your statistical reasoning (e.g. misinterpreting p-values or assuming causation where only correlation exists).\nUse your existing company style guide to generate a brand.yaml specification to automatically style your reports, apps, dashboards and plots to match your corporate style guide." + }, + { + "objectID": "index.html", + "href": "index.html", + "title": "chatlas", "section": "", - "text": "When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like. This will generally work well most of the time, but there’s no guarantee that you’ll actually get the exact format that you want. In particular, if you’re trying to get JSON, find that it’s typically surrounded in ```json, and you’ll occassionally get text that isn’t actually valid JSON. To avoid these challenges you can use a recent LLM feature: structured data (aka structured output). With structured data, you supply a type specification that exactly defines the object structure that you want and the LLM will guarantee that’s what you get back.\nimport json\nimport pandas as pd\nfrom chatlas import ChatOpenAI\nfrom pydantic import BaseModel, Field" + "text": "chatlas provides a simple and unified interface across large language model (llm) providers in Python. It abstracts away complexity from common tasks like streaming chat interfaces, tool calling, structured output, and much more. chatlas helps you prototype faster without painting you into a corner; for example, switching providers is as easy as changing one line of code, but provider specific features are still accessible when needed. Developer experience is also a key focus of chatlas: typing support, rich console output, and built-in tooling are all included.\n(Looking for something similar to chatlas, but in R? Check out elmer!)\n\n\nInstall the latest stable release from PyPI:\npip install -U chatlas\nOr, install the latest development version from GitHub:\npip install -U git+https://github.com/posit-dev/chatlas\n\n\n\nchatlas supports a variety of model providers. See the API reference for more details (like managing credentials) on each provider.\n\nAnthropic (Claude): ChatAnthropic().\nGitHub model marketplace: ChatGithub().\nGoogle (Gemini): ChatGoogle().\nGroq: ChatGroq().\nOllama local models: ChatOllama().\nOpenAI: ChatOpenAI().\nperplexity.ai: ChatPerplexity().\n\nIt also supports the following enterprise cloud providers:\n\nAWS Bedrock: ChatBedrockAnthropic().\nAzure OpenAI: ChatAzureOpenAI().\n\nTo use a model provider that isn’t listed here, you have two options:\n\nIf the model is OpenAI compatible, use ChatOpenAI() with the appropriate base_url and api_key (see ChatGithub for a reference).\nIf you’re motivated, implement a new provider by subclassing Provider and implementing the required methods.\n\n\n\n\nIf you’re using chatlas inside your organisation, you’ll be limited to what your org allows, which is likely to be one provided by a big cloud provider (e.g. ChatAzureOpenAI() and ChatBedrockAnthropic()). If you’re using chatlas for your own personal exploration, you have a lot more freedom so we have a few recommendations to help you get started:\n\nChatOpenAI() or ChatAnthropic() are both good places to start. ChatOpenAI() defaults to GPT-4o, but you can use model = \"gpt-4o-mini\" for a cheaper lower-quality model, or model = \"o1-mini\" for more complex reasoning. ChatAnthropic() is similarly good; it defaults to Claude 3.5 Sonnet which we have found to be particularly good at writing code.\nChatGoogle() is great for large prompts, because it has a much larger context window than other models. It allows up to 1 million tokens, compared to Claude 3.5 Sonnet’s 200k and GPT-4o’s 128k.\nChatOllama(), which uses Ollama, allows you to run models on your own computer. The biggest models you can run locally aren’t as good as the state of the art hosted models, but they also don’t share your data and and are effectively free.\n\n\n\n\nYou can chat via chatlas in several different ways, depending on whether you are working interactively or programmatically. They all start with creating a new chat object:\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(\n model = \"gpt-4o\",\n system_prompt = \"You are a friendly but terse assistant.\",\n)\n\n\nFrom a chat instance, it’s simple to start a web-based or terminal-based chat console, which is great for testing the capabilities of the model. In either case, responses stream in real-time, and context is preserved across turns.\nchat.app()\n\n\n\nOr, if you prefer to work from the terminal:\nchat.console()\nEntering chat console. Press Ctrl+C to quit.\n\n?> Who created Python?\n\nPython was created by Guido van Rossum. He began development in the late 1980s and released the first version in 1991. \n\n?> Where did he develop it?\n\nGuido van Rossum developed Python while working at Centrum Wiskunde & Informatica (CWI) in the Netherlands. \n\n\n\nFor a more programmatic approach, you can use the .chat() method to ask a question and get a response. By default, the response prints to a rich console as it streams in:\nchat.chat(\"What preceding languages most influenced Python?\")\nPython was primarily influenced by ABC, with additional inspiration from C,\nModula-3, and various other languages.\nTo ask a question about an image, pass one or more additional input arguments using content_image_file() and/or content_image_url():\nfrom chatlas import content_image_url\n\nchat.chat(\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n \"Can you explain this logo?\"\n)\nThe Python logo features two intertwined snakes in yellow and blue,\nrepresenting the Python programming language. The design symbolizes...\nTo get the full response as a string, use the built-in str() function. Optionally, you can also suppress the rich console output by setting echo=\"none\":\nresponse = chat.chat(\"Who is Posit?\", echo=\"none\")\nprint(str(response))\nAs we’ll see in later articles, echo=\"all\" can also be useful for debugging, as it shows additional information, such as tool calls.\n\n\n\nIf you want to do something with the response in real-time (i.e., as it arrives in chunks), use the .stream() method. This method returns an iterator that yields each chunk of the response as it arrives:\nresponse = chat.stream(\"Who is Posit?\")\nfor chunk in response:\n print(chunk, end=\"\")\nThe .stream() method can also be useful if you’re building a chatbot or other programs that needs to display responses as they arrive.\n\n\n\nTool calling is as simple as passing a function with type hints and docstring to .register_tool().\nimport sys\n\ndef get_current_python_version() -> str:\n \"\"\"Get the current version of Python.\"\"\"\n return sys.version\n\nchat.register_tool(get_current_python_version)\nchat.chat(\"What's the current version of Python?\")\nThe current version of Python is 3.13.\nLearn more in the tool calling article\n\n\n\nStructured data (i.e., structured output) is as simple as passing a pydantic model to .extract_data().\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n name: str\n age: int\n\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n{'name': 'Susan', 'age': 13}\nLearn more in the structured data article\n\n\n\nEasily get a full markdown or HTML export of a conversation:\nchat.export(\"index.html\", title=\"Python Q&A\")\nIf the export doesn’t have all the information you need, you can also access the full conversation history via the .get_turns() method:\nchat.get_turns()\nAnd, if the conversation is too long, you can specify which turns to include:\nchat.export(\"index.html\", turns=chat.get_turns()[-5:])\n\n\n\nchat methods tend to be synchronous by default, but you can use the async flavor by appending _async to the method name:\nimport asyncio\n\nasync def main():\n await chat.chat_async(\"What is the capital of France?\")\n\nasyncio.run(main())\n\n\n\nchatlas has full typing support, meaning that, among other things, autocompletion just works in your favorite editor:\n\n\n\n\n\n\nSometimes things like token limits, tool errors, or other issues can cause problems that are hard to diagnose. In these cases, the echo=\"all\" option is helpful for getting more information about what’s going on under the hood.\nchat.chat(\"What is the capital of France?\", echo=\"all\")\nThis shows important information like tool call results, finish reasons, and more.\nIf the problem isn’t self-evident, you can also reach into the .get_last_turn(), which contains the full response object, with full details about the completion.\n\n\n\nFor monitoring issues in a production (or otherwise non-interactive) environment, you may want to enabling logging. Also, since chatlas builds on top of packages like anthropic and openai, you can also enable their debug logging to get lower-level information, like HTTP requests and response codes.\n$ export CHATLAS_LOG=info\n$ export OPENAI_LOG=info\n$ export ANTHROPIC_LOG=info\n\n\n\nIf you’re new to world LLMs, you might want to read the Get Started guide, which covers some basic concepts and terminology.\nOnce you’re comfortable with the basics, you can explore more in-depth topics like prompt design or the API reference." }, { - "objectID": "structured-data.html#structured-data-basics", - "href": "structured-data.html#structured-data-basics", - "title": "Structured data", - "section": "Structured data basics", - "text": "Structured data basics\nTo extract structured data you call the .extract_data() method instead of the .chat() method. You’ll also need to define a type specification that describes the structure of the data that you want (more on that shortly). Here’s a simple example that extracts two specific values from a string:\n\nclass Person(BaseModel):\n name: str\n age: int\n\n\nchat = ChatOpenAI()\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n\n{'name': 'Susan', 'age': 13}\n\n\nThe same basic idea works with images too:\n\nfrom chatlas import content_image_url\n\nclass Image(BaseModel):\n primary_shape: str\n primary_colour: str\n\nchat.extract_data(\n content_image_url(\"https://www.r-project.org/Rlogo.png\"),\n data_model=Image,\n)\n\n{'primary_shape': 'oval and letter', 'primary_colour': 'gray and blue'}" + "objectID": "index.html#install", + "href": "index.html#install", + "title": "chatlas", + "section": "", + "text": "Install the latest stable release from PyPI:\npip install -U chatlas\nOr, install the latest development version from GitHub:\npip install -U git+https://github.com/posit-dev/chatlas" }, { - "objectID": "structured-data.html#data-types-basics", - "href": "structured-data.html#data-types-basics", - "title": "Structured data", - "section": "Data types basics", - "text": "Data types basics\nTo define your desired type specification (also known as a schema), you use a pydantic model.\nIn addition to the model definition with field names and types, you may also want to provide the LLM with an additional context about what each field/model represents. In this case, include a Field(description=\"...\") for each field, and a docstring for each model. This is a good place to ask nicely for other attributes you’ll like the value to possess (e.g. minimum or maximum values, date formats, …). You aren’t guaranteed that these requests will be honoured, but the LLM will usually make a best effort to do so.\n\nclass Person(BaseModel):\n \"\"\"A person\"\"\"\n\n name: str = Field(description=\"Name\")\n\n age: int = Field(description=\"Age, in years\")\n\n hobbies: list[str] = Field(\n description=\"List of hobbies. Should be exclusive and brief.\"\n )\n\nNow we’ll dive into some examples before coming back to talk more data types details." + "objectID": "index.html#model-providers", + "href": "index.html#model-providers", + "title": "chatlas", + "section": "", + "text": "chatlas supports a variety of model providers. See the API reference for more details (like managing credentials) on each provider.\n\nAnthropic (Claude): ChatAnthropic().\nGitHub model marketplace: ChatGithub().\nGoogle (Gemini): ChatGoogle().\nGroq: ChatGroq().\nOllama local models: ChatOllama().\nOpenAI: ChatOpenAI().\nperplexity.ai: ChatPerplexity().\n\nIt also supports the following enterprise cloud providers:\n\nAWS Bedrock: ChatBedrockAnthropic().\nAzure OpenAI: ChatAzureOpenAI().\n\nTo use a model provider that isn’t listed here, you have two options:\n\nIf the model is OpenAI compatible, use ChatOpenAI() with the appropriate base_url and api_key (see ChatGithub for a reference).\nIf you’re motivated, implement a new provider by subclassing Provider and implementing the required methods." }, { - "objectID": "structured-data.html#examples", - "href": "structured-data.html#examples", - "title": "Structured data", - "section": "Examples", - "text": "Examples\nThe following examples are closely inspired by the Claude documentation and hint at some of the ways you can use structured data extraction.\n\nExample 1: Article summarisation\n\nwith open(\"examples/third-party-testing.txt\") as f:\n text = f.read()\n\n\nclass ArticleSummary(BaseModel):\n \"\"\"Summary of the article.\"\"\"\n\n author: str = Field(description=\"Name of the article author\")\n\n topics: list[str] = Field(\n description=\"Array of topics, e.g. ['tech', 'politics']. Should be as specific as possible, and can overlap.\"\n )\n\n summary: str = Field(description=\"Summary of the article. One or two paragraphs max\")\n\n coherence: int = Field(\n description=\"Coherence of the article's key points, 0-100 (inclusive)\"\n )\n\n persuasion: float = Field(\n description=\"Article's persuasion score, 0.0-1.0 (inclusive)\"\n )\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=ArticleSummary)\nprint(json.dumps(data, indent=2))\n\n{\n \"author\": \"N/A\",\n \"topics\": [\n \"AI policy\",\n \"third-party testing\",\n \"technology safety\",\n \"regulatory capture\",\n \"AI regulation\"\n ],\n \"summary\": \"The article discusses the importance of implementing a robust third-party testing regime for frontier AI systems to ensure their safety and mitigate the risks of societal harm. It emphasizes the need for involvement from industry, government, and academia to develop standards and procedures for testing. Third-party testing is considered critical for addressing potential misuse or accidents associated with large-scale generative AI models. The article outlines the goals of developing an effective testing regime, which includes building trust, ensuring safety measures for powerful systems, and promoting coordination between countries. There is also discussion about balancing transparency and preventing harmful uses, as well as the potential for regulatory capture. Ultimately, this testing regime aims to complement sector-specific regulations and enable effective oversight of AI development.\",\n \"coherence\": 85,\n \"persuasion\": 0.89\n}\n\n\n\n\nExample 2: Named entity recognition\n\ntext = \"John works at Google in New York. He met with Sarah, the CEO of Acme Inc., last week in San Francisco.\"\n\n\nclass NamedEntity(BaseModel):\n \"\"\"Named entity in the text.\"\"\"\n\n name: str = Field(description=\"The extracted entity name\")\n\n type_: str = Field(description=\"The entity type, e.g. 'person', 'location', 'organization'\")\n\n context: str = Field(description=\"The context in which the entity appears in the text.\")\n\n\nclass NamedEntities(BaseModel):\n \"\"\"Named entities in the text.\"\"\"\n\n entities: list[NamedEntity] = Field(description=\"Array of named entities\")\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=NamedEntities)\npd.DataFrame(data[\"entities\"])\n\n\n\n\n\n\n\n\nname\ntype_\ncontext\n\n\n\n\n0\nJohn\nperson\nJohn works at Google in New York.\n\n\n1\nGoogle\norganization\nJohn works at Google in New York.\n\n\n2\nNew York\nlocation\nJohn works at Google in New York.\n\n\n3\nSarah\nperson\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n4\nAcme Inc.\norganization\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n5\nSan Francisco\nlocation\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n\n\n\n\n\n\n\nExample 3: Sentiment analysis\n\ntext = \"The product was okay, but the customer service was terrible. I probably won't buy from them again.\"\n\nclass Sentiment(BaseModel):\n \"\"\"Extract the sentiment scores of a given text. Sentiment scores should sum to 1.\"\"\"\n\n positive_score: float = Field(\n description=\"Positive sentiment score, ranging from 0.0 to 1.0\"\n )\n\n negative_score: float = Field(\n description=\"Negative sentiment score, ranging from 0.0 to 1.0\"\n )\n\n neutral_score: float = Field(\n description=\"Neutral sentiment score, ranging from 0.0 to 1.0\"\n )\n\n\nchat = ChatOpenAI()\nchat.extract_data(text, data_model=Sentiment)\n\n{'positive_score': 0.1, 'negative_score': 0.7, 'neutral_score': 0.2}\n\n\nNote that we’ve asked nicely for the scores to sum 1, and they do in this example (at least when I ran the code), but it’s not guaranteed.\n\n\nExample 4: Text classification\n\nfrom typing import Literal\n\ntext = \"The new quantum computing breakthrough could revolutionize the tech industry.\"\n\n\nclass Classification(BaseModel):\n\n name: Literal[\n \"Politics\", \"Sports\", \"Technology\", \"Entertainment\", \"Business\", \"Other\"\n ] = Field(description=\"The category name\")\n\n score: float = Field(description=\"The classification score for the category, ranging from 0.0 to 1.0.\")\n\n\nclass Classifications(BaseModel):\n \"\"\"Array of classification results. The scores should sum to 1.\"\"\"\n\n classifications: list[Classification]\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=Classifications)\npd.DataFrame(data[\"classifications\"])\n\n\n\n\n\n\n\n\nname\nscore\n\n\n\n\n0\nTechnology\n0.7\n\n\n1\nBusiness\n0.2\n\n\n2\nOther\n0.1\n\n\n\n\n\n\n\n\n\nExample 5: Working with unknown keys\n\nfrom chatlas import ChatAnthropic\n\n\nclass Characteristics(BaseModel, extra=\"allow\"):\n \"\"\"All characteristics\"\"\"\n\n pass\n\n\nprompt = \"\"\"\n Given a description of a character, your task is to extract all the characteristics of that character.\n\n <description>\n The man is tall, with a beard and a scar on his left cheek. He has a deep voice and wears a black leather jacket.\n </description>\n\"\"\"\n\nchat = ChatAnthropic()\ndata = chat.extract_data(prompt, data_model=Characteristics)\nprint(json.dumps(data, indent=2))\n\n{\n \"appearance\": {\n \"height\": \"tall\",\n \"facial_features\": {\n \"beard\": true,\n \"scar\": {\n \"location\": \"left cheek\"\n }\n },\n \"voice\": \"deep\",\n \"clothing\": {\n \"outerwear\": {\n \"type\": \"leather jacket\",\n \"color\": \"black\"\n }\n }\n }\n}\n\n\nThis example only works with Claude, not GPT or Gemini, because only Claude supports adding arbitrary additional properties.\n\n\nExample 6: Extracting data from an image\nThis example comes from Dan Nguyen and you can see other interesting applications at that link. The goal is to extract structured data from this screenshot:\nThe goal is to extract structured data from this screenshot:\n\n\n\nA screenshot of schedule A: a table showing assets and “unearned” income\n\n\nEven without any descriptions, ChatGPT does pretty well:\n\nfrom chatlas import content_image_file\n\n\nclass Asset(BaseModel):\n assert_name: str\n owner: str\n location: str\n asset_value_low: int\n asset_value_high: int\n income_type: str\n income_low: int\n income_high: int\n tx_gt_1000: bool\n\n\nclass DisclosureReport(BaseModel):\n assets: list[Asset]\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(\n content_image_file(\"images/congressional-assets.png\"), data_model=DisclosureReport\n)\npd.DataFrame(data[\"assets\"])\n\n\n\n\n\n\n\n\nassert_name\nowner\nlocation\nasset_value_low\nasset_value_high\nincome_type\nincome_low\nincome_high\ntx_gt_1000\n\n\n\n\n0\n11 Zinfandel Lane - Home & Vineyard [RP]\nJT\nSt. Helena/Napa, CA, US\n5000001\n25000000\nGrape Sales\n100001\n1000000\nTrue\n\n\n1\n25 Point Lobos - Commercial Property [RP]\nSP\nSan Francisco/San Francisco, CA, US\n5000001\n25000000\nRent\n100001\n1000000\nFalse" + "objectID": "index.html#model-choice", + "href": "index.html#model-choice", + "title": "chatlas", + "section": "", + "text": "If you’re using chatlas inside your organisation, you’ll be limited to what your org allows, which is likely to be one provided by a big cloud provider (e.g. ChatAzureOpenAI() and ChatBedrockAnthropic()). If you’re using chatlas for your own personal exploration, you have a lot more freedom so we have a few recommendations to help you get started:\n\nChatOpenAI() or ChatAnthropic() are both good places to start. ChatOpenAI() defaults to GPT-4o, but you can use model = \"gpt-4o-mini\" for a cheaper lower-quality model, or model = \"o1-mini\" for more complex reasoning. ChatAnthropic() is similarly good; it defaults to Claude 3.5 Sonnet which we have found to be particularly good at writing code.\nChatGoogle() is great for large prompts, because it has a much larger context window than other models. It allows up to 1 million tokens, compared to Claude 3.5 Sonnet’s 200k and GPT-4o’s 128k.\nChatOllama(), which uses Ollama, allows you to run models on your own computer. The biggest models you can run locally aren’t as good as the state of the art hosted models, but they also don’t share your data and and are effectively free." }, { - "objectID": "structured-data.html#advanced-data-types", - "href": "structured-data.html#advanced-data-types", - "title": "Structured data", - "section": "Advanced data types", - "text": "Advanced data types\nNow that you’ve seen a few examples, it’s time to get into more specifics about data type declarations.\n\nRequired vs optional\nBy default, model fields are in a sense “required”, unless None is allowed in their type definition. Including None is a good idea if there’s any possibility of the input not containing the required fields as LLMs may hallucinate data in order to fulfill your spec.\nFor example, here the LLM hallucinates a date even though there isn’t one in the text:\n\nclass ArticleSpec(BaseModel):\n \"\"\"Information about an article written in markdown\"\"\"\n\n title: str = Field(description=\"Article title\")\n author: str = Field(description=\"Name of the author\")\n date: str = Field(description=\"Date written in YYYY-MM-DD format.\")\n\n\nprompt = \"\"\"\n Extract data from the following text:\n\n <text>\n # Structured Data\n By Hadley Wickham\n\n When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like.\n </text>\n\"\"\"\n\nchat = ChatOpenAI()\ndata = chat.extract_data(prompt, data_model=ArticleSpec)\nprint(json.dumps(data, indent=2))\n\n{\n \"title\": \"Structured Data\",\n \"author\": \"Hadley Wickham\",\n \"date\": \"2023-10-07\"\n}\n\n\nNote that I’ve used more of an explict prompt here. For this example, I found that this generated better results, and it’s a useful place to put additional instructions.\nIf let the LLM know that the fields are all optional, it’ll instead return None for the missing fields:\n\nclass ArticleSpec(BaseModel):\n \"\"\"Information about an article written in markdown\"\"\"\n\n title: str = Field(description=\"Article title\")\n author: str = Field(description=\"Name of the author\")\n date: str | None = Field(description=\"Date written in YYYY-MM-DD format.\")\n\n\ndata = chat.extract_data(prompt, data_model=ArticleSpec)\nprint(json.dumps(data, indent=2))\n\n{\n \"title\": \"Structured Data\",\n \"author\": \"Hadley Wickham\",\n \"date\": null\n}\n\n\n\n\nData frames\nIf you want to define a data frame like data_model, you might be tempted to create a model like this, where each field is a list of scalar values:\nclass Persons(BaseModel):\n name: list[str]\n age: list[int]\nThis however, is not quite right because there’s no way to specify that each field should have the same length. Instead you need to turn the data structure “inside out”, and instead create an array of objects:\nclass Person(BaseModel):\n name: str\n age: int\n\nclass Persons(BaseModel):\n persons: list[Person]\nIf you’re familiar with the terms between row-oriented and column-oriented data frames, this is the same idea." + "objectID": "index.html#using-chatlas", + "href": "index.html#using-chatlas", + "title": "chatlas", + "section": "", + "text": "You can chat via chatlas in several different ways, depending on whether you are working interactively or programmatically. They all start with creating a new chat object:\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(\n model = \"gpt-4o\",\n system_prompt = \"You are a friendly but terse assistant.\",\n)\n\n\nFrom a chat instance, it’s simple to start a web-based or terminal-based chat console, which is great for testing the capabilities of the model. In either case, responses stream in real-time, and context is preserved across turns.\nchat.app()\n\n\n\nOr, if you prefer to work from the terminal:\nchat.console()\nEntering chat console. Press Ctrl+C to quit.\n\n?> Who created Python?\n\nPython was created by Guido van Rossum. He began development in the late 1980s and released the first version in 1991. \n\n?> Where did he develop it?\n\nGuido van Rossum developed Python while working at Centrum Wiskunde & Informatica (CWI) in the Netherlands. \n\n\n\nFor a more programmatic approach, you can use the .chat() method to ask a question and get a response. By default, the response prints to a rich console as it streams in:\nchat.chat(\"What preceding languages most influenced Python?\")\nPython was primarily influenced by ABC, with additional inspiration from C,\nModula-3, and various other languages.\nTo ask a question about an image, pass one or more additional input arguments using content_image_file() and/or content_image_url():\nfrom chatlas import content_image_url\n\nchat.chat(\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n \"Can you explain this logo?\"\n)\nThe Python logo features two intertwined snakes in yellow and blue,\nrepresenting the Python programming language. The design symbolizes...\nTo get the full response as a string, use the built-in str() function. Optionally, you can also suppress the rich console output by setting echo=\"none\":\nresponse = chat.chat(\"Who is Posit?\", echo=\"none\")\nprint(str(response))\nAs we’ll see in later articles, echo=\"all\" can also be useful for debugging, as it shows additional information, such as tool calls.\n\n\n\nIf you want to do something with the response in real-time (i.e., as it arrives in chunks), use the .stream() method. This method returns an iterator that yields each chunk of the response as it arrives:\nresponse = chat.stream(\"Who is Posit?\")\nfor chunk in response:\n print(chunk, end=\"\")\nThe .stream() method can also be useful if you’re building a chatbot or other programs that needs to display responses as they arrive.\n\n\n\nTool calling is as simple as passing a function with type hints and docstring to .register_tool().\nimport sys\n\ndef get_current_python_version() -> str:\n \"\"\"Get the current version of Python.\"\"\"\n return sys.version\n\nchat.register_tool(get_current_python_version)\nchat.chat(\"What's the current version of Python?\")\nThe current version of Python is 3.13.\nLearn more in the tool calling article\n\n\n\nStructured data (i.e., structured output) is as simple as passing a pydantic model to .extract_data().\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n name: str\n age: int\n\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n{'name': 'Susan', 'age': 13}\nLearn more in the structured data article\n\n\n\nEasily get a full markdown or HTML export of a conversation:\nchat.export(\"index.html\", title=\"Python Q&A\")\nIf the export doesn’t have all the information you need, you can also access the full conversation history via the .get_turns() method:\nchat.get_turns()\nAnd, if the conversation is too long, you can specify which turns to include:\nchat.export(\"index.html\", turns=chat.get_turns()[-5:])\n\n\n\nchat methods tend to be synchronous by default, but you can use the async flavor by appending _async to the method name:\nimport asyncio\n\nasync def main():\n await chat.chat_async(\"What is the capital of France?\")\n\nasyncio.run(main())\n\n\n\nchatlas has full typing support, meaning that, among other things, autocompletion just works in your favorite editor:\n\n\n\n\n\n\nSometimes things like token limits, tool errors, or other issues can cause problems that are hard to diagnose. In these cases, the echo=\"all\" option is helpful for getting more information about what’s going on under the hood.\nchat.chat(\"What is the capital of France?\", echo=\"all\")\nThis shows important information like tool call results, finish reasons, and more.\nIf the problem isn’t self-evident, you can also reach into the .get_last_turn(), which contains the full response object, with full details about the completion.\n\n\n\nFor monitoring issues in a production (or otherwise non-interactive) environment, you may want to enabling logging. Also, since chatlas builds on top of packages like anthropic and openai, you can also enable their debug logging to get lower-level information, like HTTP requests and response codes.\n$ export CHATLAS_LOG=info\n$ export OPENAI_LOG=info\n$ export ANTHROPIC_LOG=info\n\n\n\nIf you’re new to world LLMs, you might want to read the Get Started guide, which covers some basic concepts and terminology.\nOnce you’re comfortable with the basics, you can explore more in-depth topics like prompt design or the API reference." }, { - "objectID": "structured-data.html#token-usage", - "href": "structured-data.html#token-usage", - "title": "Structured data", - "section": "Token usage", - "text": "Token usage\nBelow is a summary of the tokens used to create the output in this example.\n\nfrom chatlas import token_usage\ntoken_usage()\n\n[{'name': 'OpenAI', 'input': 6081, 'output': 615},\n {'name': 'Anthropic', 'input': 463, 'output': 137}]" + "objectID": "tool-calling.html", + "href": "tool-calling.html", + "title": "Introduction", + "section": "", + "text": "One of the most interesting aspects of modern chat models is their ability to make use of external tools that are defined by the caller.\nWhen making a chat request to the chat model, the caller advertises one or more tools (defined by their function name, description, and a list of expected arguments), and the chat model can choose to respond with one or more “tool calls”. These tool calls are requests from the chat model to the caller to execute the function with the given arguments; the caller is expected to execute the functions and “return” the results by submitting another chat request with the conversation so far, plus the results. The chat model can then use those results in formulating its response, or, it may decide to make additional tool calls.\nNote that the chat model does not directly execute any external tools! It only makes requests for the caller to execute them. It’s easy to think that tool calling might work like this:\n\n\n\nDiagram showing showing the wrong mental model of tool calls: a user initiates a request that flows to the assistant, which then runs the code, and returns the result back to the user.”\n\n\nBut in fact it works like this:\n\n\n\nDiagram showing the correct mental model for tool calls: a user sends a request that needs a tool call, the assistant request that the user’s runs that tool, returns the result to the assistant, which uses it to generate the final answer.\n\n\nThe value that the chat model brings is not in helping with execution, but with knowing when it makes sense to call a tool, what values to pass as arguments, and how to use the results in formulating its response.\n\nfrom chatlas import ChatOpenAI\n\n\nMotivating example\nLet’s take a look at an example where we really need an external tool. Chat models generally do not have access to “real-time” information, such as current events, weather, etc. Let’s see what happens when we ask the chat model about the weather in a specific location:\n\nchat = ChatOpenAI(model=\"gpt-4o-mini\")\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\nI’m unable to provide real-time weather updates. To get the current weather in Duluth, MN, I recommend checking a reliable weather website or app.\n\n\nFortunately, the model is smart enough to know that it doesn’t have access to real-time information, and it doesn’t try to make up an answer. However, we can help it out by providing a tool that can fetch the weather for a given location.\n\n\nDefining a tool function\nAt it turns out, LLMs are pretty good at figuring out ‘structure’ like latitude and longitude from ‘unstructured’ things like a location name. So we can write a tool function that takes a latitude and longitude and returns the current temperature at that location. Here’s an example of how you might write such a function using the Open-Meteo API:\n\nimport requests\n\ndef get_current_temperature(latitude: float, longitude: float):\n \"\"\"\n Get the current weather given a latitude and longitude.\n\n Parameters\n ----------\n latitude\n The latitude of the location.\n longitude\n The longitude of the location.\n \"\"\"\n lat_lng = f\"latitude={latitude}&longitude={longitude}\"\n url = f\"https://api.open-meteo.com/v1/forecast?{lat_lng}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m\"\n response = requests.get(url)\n json = response.json()\n return json[\"current\"]\n\nNote that we’ve gone through the trouble of adding the following to our function:\n\nType hints for function arguments\nA docstring that explains what the function does and what arguments it expects (as well as descriptions for the arguments themselves)\n\nProviding these hints and documentation is very important, as it helps the chat model understand how to use your tool correctly!\nLet’s test it:\n\nget_current_temperature(46.7867, -92.1005)\n\n{'time': '2024-12-13T22:45',\n 'interval': 900,\n 'temperature_2m': -11.5,\n 'wind_speed_10m': 9.4}\n\n\n\n\nUsing the tool\nIn order for the LLM to make use of our tool, we need to register it with the chat object. This is done by calling the register_tool method on the chat object.\n\nchat.register_tool(get_current_temperature)\n\nNow let’s retry our original question:\n\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\n\nThe current weather in Duluth, MN, is approximately -11.3°C with a wind speed of 9.4 km/h.\n\n\nThat’s correct! Without any further guidance, the chat model decided to call our tool function and successfully used its result in formulating its response.\nThis tool example was extremely simple, but you can imagine doing much more interesting things from tool functions: calling APIs, reading from or writing to a database, kicking off a complex simulation, or even calling a complementary GenAI model (like an image generator). Or if you are using chatlas in a Shiny app, you could use tools to set reactive values, setting off a chain of reactive updates. This is precisely what the sidebot dashboard does to allow for an AI assisted “drill-down” into the data.\n\n\nTrouble-shooting\nWhen the execution of a tool function fails, chatlas sends the exception message back to the chat model. This can be useful for gracefully handling errors in the chat model. However, this can also lead to confusion as to why a response did not come back as expected. If you encounter such a situation, you can set echo=\"all\" in the chat.chat() method to see the full conversation, including tool calls and their results.\n\ndef get_current_temperature(latitude: float, longitude: float):\n \"Get the current weather given a latitude and longitude.\"\n raise ValueError(\"Failed to get current temperature\")\n\nchat.register_tool(get_current_temperature)\n\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\n\nI encountered an issue while trying to retrieve the current weather for Duluth, MN. Please check a reliable weather website or app for the latest updates.\n\n\n\n\nTool limitations\nRemember that tool arguments come from the chat model, and tool results are returned to the chat model. That means that only simple, JSON-compatible data types can be used as inputs and outputs. It’s highly recommended that you stick to basic types for each function parameter (e.g. str, float/int, bool, None, list, tuple, dict). And you can forget about using functions, classes, external pointers, and other complex (i.e., non-serializable) Python objects as arguments or return values. Returning data frames seems to work OK (as long as you return the JSON representation – .to_json()), although be careful not to return too much data, as it all counts as tokens (i.e., they count against your context window limit and also cost you money)." }, { "objectID": "prompt-design.html", @@ -872,918 +923,874 @@ "href": "prompt-design.html#code-generation", "title": "Prompt design", "section": "Code generation", - "text": "Code generation\nLet’s explore prompt design for a simple code generation task:\n\nfrom chatlas import ChatAnthropic, ChatOpenAI\n\nquestion = \"\"\"\n How can I compute the mean and median of variables a, b, c, and so on,\n all the way up to z, grouped by age and sex.\n\"\"\"\n\n\nBasic flavour\nWhen I don’t provide a system prompt, I sometimes get answers in a different language (like R):\n\nchat = ChatAnthropic()\n_ = chat.chat(question)\n\n\n\n\n\n\n\nHere’s how to compute mean and median for variables a through z, grouped by age and sex:\n# Using dplyr\nlibrary(dplyr)\n\ndf %>%\n group_by(age, sex) %>%\n summarise(across(a:z, list(\n mean = ~mean(., na.rm = TRUE),\n median = ~median(., na.rm = TRUE)\n )))\n\n# Alternative base R approach\naggregate(. ~ age + sex, data = df[,c(\"age\", \"sex\", letters[1:26])], \n FUN = function(x) c(mean = mean(x), median = median(x)))\nThis will: 1. Group the data by age and sex 2. Calculate both mean and median for each variable a through z 3. Handle missing values with na.rm = TRUE 4. Return a dataframe with results for each age-sex combination\nThe output will have columns for age, sex, and mean/median values for each variable.\n\n\nI can ensure that I always get Python code by providing a system prompt:\n\nchat.system_prompt = \"You are a helpful Python (not R) programming assistant.\"\n_ = chat.chat(question)\n\n\n\n\n\nHere’s how to compute mean and median for variables a through z in Python using pandas:\nimport pandas as pd\n\n# Assuming your data is in a DataFrame called df\n# Group by age and sex, then calculate mean and median for all variables a through z\nresult = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median'])\n\n# If you want to handle missing values:\nresult = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg({\n col: ['mean', 'median'] for col in list('abcdefghijklmnopqrstuvwxyz')\n}).fillna(0) # or use .dropna() instead of fillna() if you prefer to remove NaN values\n\n# To make the output more readable, you can flatten the column names:\nresult.columns = [f'{col}_{stat}' for col, stat in result.columns]\nThis will: 1. Group your data by age and sex 2. Calculate mean and median for each variable from ‘a’ to ‘z’ 3. Return a DataFrame where: - The index will be the age and sex combinations - The columns will be each variable’s mean and median - Column names will be in the format ‘variable_statistic’ (e.g., ‘a_mean’, ‘a_median’, etc.)\nExample output might look like:\n a_mean a_median b_mean b_median ... z_mean z_median\nage sex ...\n20 M 23.5 24.0 45.2 46.0 ... 12.3 12.0\n F 22.1 21.0 44.8 45.0 ... 11.9 12.0\n21 M 24.2 25.0 46.1 46.0 ... 12.5 13.0\n F 23.8 24.0 45.9 46.0 ... 12.2 12.0\n...\n\n\nNote that I’m using both a system prompt (which defines the general behaviour) and a user prompt (which asks the specific question). You could put all of the content in the user prompt and get similar results, but I think it’s helpful to use both to cleanly divide the general framing of the response from the specific questions that you want to ask.\nSince I’m mostly interested in the code, I ask it to drop the explanation:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant.\n Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport pandas as pd\n\nresult = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median'])\nresult.columns = [f'{col}_{stat}' for col, stat in result.columns]\n\n\nIn this case, I seem to mostly get pandas code. But if you want a different style, you can ask for it:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant who prefers polars to pandas.\n Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport polars as pl\n\nresult = df.groupby(['age', 'sex']).agg([\n pl.col(c).mean().alias(f'{c}_mean') for c in 'abcdefghijklmnopqrstuvwxyz'\n] + [\n pl.col(c).median().alias(f'{c}_median') for c in 'abcdefghijklmnopqrstuvwxyz'\n])\n\n\n\n\nBe explicit\nIf there’s something about the output that you don’t like, you can try being more explicit about it. For example, the code isn’t styled quite how I like, so I provide more details about what I do want:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant who prefers siuba to pandas.\n Just give me the code. I don't want any explanation or sample data.\n * Spread long function calls across multiple lines.\n * Where needed, always indent function calls with two spaces.\n * Always use double quotes for strings.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nfrom siuba import *\nfrom siuba.dply.vector import *\n\nresult = (df \n >> group_by(_.age, _.sex)\n >> summarize(**{\n f\"{col}_{stat}\": call(stat, _[col])\n for col in \"abcdefghijklmnopqrstuvwxyz\"\n for stat in [\"mean\", \"median\"]\n }))\n\n\nThis still doesn’t yield exactly the code that I’d write, but it’s prety close.\nYou could provide a different prompt if you were looking for more explanation of the code:\n\nchat.system_prompt = \"\"\"\n You are an an expert Python (not R) programmer and a warm and supportive teacher.\n Help me understand the code you produce by explaining each function call with\n a brief comment. For more complicated calls, add documentation to each\n argument. Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport pandas as pd\n\n# Create list of letters a-z to use as column names\ncols = list('abcdefghijklmnopqrstuvwxyz')\n\n# Group by age & sex, compute mean and median for all letter columns\nresult = df.groupby(['age', 'sex'])[cols].agg([\n 'mean', # Calculate mean for each column\n 'median' # Calculate median for each column\n])\n\n# Flatten the multi-level column names for readability \nresult.columns = [f'{col}_{stat}' for col, stat in result.columns]\n\n\n\n\nTeach it about new features\nYou can imagine LLMs as being a sort of an average of the internet at a given point in time. That means they will provide popular answers, which will tend to reflect older coding styles (either because the new features aren’t in their index, or the older features are so much more popular). So if you want your code to use specific newer language features, you might need to provide the examples yourself:\n\nchat.system_prompt = \"\"\"\n You are an expert R programmer.\n Just give me the code; no explanation in text.\n Use the `.by` argument rather than `group_by()`.\n dplyr 1.1.0 introduced per-operation grouping with the `.by` argument.\n e.g., instead of:\n\n transactions |>\n group_by(company, year) |>\n mutate(total = sum(revenue))\n\n write this:\n transactions |>\n mutate(\n total = sum(revenue),\n .by = c(company, year)\n )\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\ndf |>\n summarise(\n across(a:z, list(\n mean = \\(x) mean(x, na.rm = TRUE),\n median = \\(x) median(x, na.rm = TRUE)\n )),\n .by = c(age, sex)\n )" + "text": "Code generation\nLet’s explore prompt design for a simple code generation task:\n\nfrom chatlas import ChatAnthropic, ChatOpenAI\n\nquestion = \"\"\"\n How can I compute the mean and median of variables a, b, c, and so on,\n all the way up to z, grouped by age and sex.\n\"\"\"\n\n\nBasic flavour\nWhen I don’t provide a system prompt, I sometimes get answers in a different language (like R):\n\nchat = ChatAnthropic()\n_ = chat.chat(question)\n\n\n\n\n\n\n\nHere’s how to compute mean and median for variables a through z, grouped by age and sex:\n# Using dplyr\nlibrary(dplyr)\n\ndf %>%\n group_by(age, sex) %>%\n summarise(across(a:z, list(\n mean = ~mean(., na.rm = TRUE),\n median = ~median(., na.rm = TRUE)\n )))\n\n# Alternative base R approach\naggregate(. ~ age + sex, data = df[,c(\"age\", \"sex\", letters)], \n FUN = function(x) c(mean = mean(x), median = median(x)))\nThis will: 1. Group the data by age and sex 2. Calculate both mean and median for each variable a through z 3. Handle missing values with na.rm = TRUE 4. Return a dataframe with results for each age-sex combination\nThe output will have columns for age, sex, and mean/median values for each variable.\n\n\nI can ensure that I always get Python code by providing a system prompt:\n\nchat.system_prompt = \"You are a helpful Python (not R) programming assistant.\"\n_ = chat.chat(question)\n\n\n\n\n\nHere’s how to compute mean and median for variables a through z using Python, likely with pandas:\nimport pandas as pd\n\n# Assuming your data is in a DataFrame called df\nresult = df.groupby(['age', 'sex'])[list('abcdefghijklmnopqrstuvwxyz')].agg(['mean', 'median'])\n\n# If you want to reset the index to make age and sex regular columns\nresult = result.reset_index()\n\n# Alternative way with more explicit column selection:\ncolumns_to_analyze = [chr(i) for i in range(ord('a'), ord('z')+1)]\nresult = df.groupby(['age', 'sex'])[columns_to_analyze].agg(['mean', 'median'])\nThis will: 1. Group the data by age and sex 2. Calculate both mean and median for each variable from ‘a’ to ‘z’ 3. Handle missing values automatically 4. Create a multi-level column structure where each variable has both mean and median\nThe resulting DataFrame will have: - age and sex as index (unless reset_index() is used) - A hierarchical column structure where each variable (a-z) has both mean and median values\nIf you need to handle missing values differently, you can modify the aggregation like this:\nresult = df.groupby(['age', 'sex'])[columns_to_analyze].agg({\n col: ['mean', 'median'] for col in columns_to_analyze\n}).dropna() # or use .fillna(0) to replace NAs with zeros\n\n\nNote that I’m using both a system prompt (which defines the general behaviour) and a user prompt (which asks the specific question). You could put all of the content in the user prompt and get similar results, but I think it’s helpful to use both to cleanly divide the general framing of the response from the specific questions that you want to ask.\nSince I’m mostly interested in the code, I ask it to drop the explanation:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant.\n Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport pandas as pd\n\ncolumns_to_analyze = list('abcdefghijklmnopqrstuvwxyz')\nresult = df.groupby(['age', 'sex'])[columns_to_analyze].agg(['mean', 'median'])\nresult = result.reset_index()\n\n\nIn this case, I seem to mostly get pandas code. But if you want a different style, you can ask for it:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant who prefers polars to pandas.\n Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport polars as pl\n\ncolumns_to_analyze = list('abcdefghijklmnopqrstuvwxyz')\nresult = (df.groupby(['age', 'sex'])\n .agg([pl.col(col).mean().alias(f'{col}_mean') for col in columns_to_analyze] +\n [pl.col(col).median().alias(f'{col}_median') for col in columns_to_analyze]))\n\n\n\n\nBe explicit\nIf there’s something about the output that you don’t like, you can try being more explicit about it. For example, the code isn’t styled quite how I like, so I provide more details about what I do want:\n\nchat.system_prompt = \"\"\"\n You are a helpful Python (not R) programming assistant who prefers siuba to pandas.\n Just give me the code. I don't want any explanation or sample data.\n * Spread long function calls across multiple lines.\n * Where needed, always indent function calls with two spaces.\n * Always use double quotes for strings.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nfrom siuba import _, group_by, summarize\nfrom siuba.siu import call\nimport pandas as pd\n\nresult = (df\n >> group_by(_.age, _.sex)\n >> summarize(**{\n f\"{col}_{agg}\": call(agg, _[col])\n for col in \"abcdefghijklmnopqrstuvwxyz\"\n for agg in [\"mean\", \"median\"]\n }))\n\n\nThis still doesn’t yield exactly the code that I’d write, but it’s prety close.\nYou could provide a different prompt if you were looking for more explanation of the code:\n\nchat.system_prompt = \"\"\"\n You are an an expert Python (not R) programmer and a warm and supportive teacher.\n Help me understand the code you produce by explaining each function call with\n a brief comment. For more complicated calls, add documentation to each\n argument. Just give me the code without any text explanation.\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\nimport pandas as pd\n\n# Generate list of letter columns a through z\ncols = list('abcdefghijklmnopqrstuvwxyz')\n\n# Group by age and sex, calculate mean and median for each letter column\nresult = (df\n .groupby(['age', 'sex'])[cols] # Group by age/sex and select letter columns\n .agg(['mean', 'median']) # Calculate both mean and median \n .reset_index() # Convert age/sex back to regular columns\n)\n\n\n\n\nTeach it about new features\nYou can imagine LLMs as being a sort of an average of the internet at a given point in time. That means they will provide popular answers, which will tend to reflect older coding styles (either because the new features aren’t in their index, or the older features are so much more popular). So if you want your code to use specific newer language features, you might need to provide the examples yourself:\n\nchat.system_prompt = \"\"\"\n You are an expert R programmer.\n Just give me the code; no explanation in text.\n Use the `.by` argument rather than `group_by()`.\n dplyr 1.1.0 introduced per-operation grouping with the `.by` argument.\n e.g., instead of:\n\n transactions |>\n group_by(company, year) |>\n mutate(total = sum(revenue))\n\n write this:\n transactions |>\n mutate(\n total = sum(revenue),\n .by = c(company, year)\n )\n\"\"\"\n_ = chat.chat(question)\n\n\n\n\n\ndf |>\n summarise(\n across(a:z, list(\n mean = \\(x) mean(x, na.rm = TRUE),\n median = \\(x) median(x, na.rm = TRUE)\n )),\n .by = c(age, sex)\n )" }, { "objectID": "prompt-design.html#structured-data", "href": "prompt-design.html#structured-data", "title": "Prompt design", "section": "Structured data", - "text": "Structured data\nProviding a rich set of examples is a great way to encourage the output to produce exactly what you want. This is known as multi-shot prompting. Below we’ll work through a prompt that I designed to extract structured data from recipes, but the same ideas apply in many other situations.\n\nGetting started\nMy overall goal is to turn a list of ingredients, like the following, into a nicely structured JSON that I can then analyse in Python (e.g. compute the total weight, scale the recipe up or down, or convert the units from volumes to weights).\n\ningredients = \"\"\"\n ¾ cup (150g) dark brown sugar\n 2 large eggs\n ¾ cup (165g) sour cream\n ½ cup (113g) unsalted butter, melted\n 1 teaspoon vanilla extract\n ¾ teaspoon kosher salt\n ⅓ cup (80ml) neutral oil\n 1½ cups (190g) all-purpose flour\n 150g plus 1½ teaspoons sugar\n\"\"\"\nchat = ChatOpenAI(model=\"gpt-4o-mini\")\n\n(This isn’t the ingredient list for a real recipe but it includes a sampling of styles that I encountered in my project.)\nIf you don’t have strong feelings about what the data structure should look like, you can start with a very loose prompt and see what you get back. I find this a useful pattern for underspecified problems where the heavy lifting lies with precisely defining the problem you want to solve. Seeing the LLM’s attempt to create a data structure gives me something to react to, rather than having to start from a blank page.\n\ninstruct_json = \"\"\"\n You're an expert baker who also loves JSON. I am going to give you a list of\n ingredients and your job is to return nicely structured JSON. Just return the\n JSON and no other commentary.\n\"\"\"\nchat.system_prompt = instruct_json\n_ = chat.chat(ingredients)\n\n\n\n\n\n{ “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: “¾ cup”, “weight”: “150g” }, { “name”: “large eggs”, “quantity”: “2” }, { “name”: “sour cream”, “quantity”: “¾ cup”, “weight”: “165g” }, { “name”: “unsalted butter”, “quantity”: “½ cup”, “weight”: “113g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: “1 teaspoon” }, { “name”: “kosher salt”, “quantity”: “¾ teaspoon” }, { “name”: “neutral oil”, “quantity”: “⅓ cup”, “volume”: “80ml” }, { “name”: “all-purpose flour”, “quantity”: “1½ cups”, “weight”: “190g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons” } ] }\n\n\n(I don’t know if the additional colour, “You’re an expert baker who also loves JSON”, does anything, but I like to think this helps the LLM get into the right mindset of a very nerdy baker.)\n\n\nProvide examples\nThis isn’t a bad start, but I prefer to cook with weight and I only want to see volumes if weight isn’t available so I provide a couple of examples of what I’m looking for. I was pleasantly suprised that I can provide the input and output examples in such a loose format.\n\ninstruct_weight = \"\"\"\n Here are some examples of the sort of output I'm looking for:\n\n ¾ cup (150g) dark brown sugar\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\"}\n\n ⅓ cup (80ml) neutral oil\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\"}\n\n 2 t ground cinnamon\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\"}\n\"\"\"\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight\n_ = chat.chat(ingredients)\n\n\n\n\n\n{ “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: 150, “unit”: “g” }, { “name”: “large eggs”, “quantity”: 2, “unit”: “count” }, { “name”: “sour cream”, “quantity”: 165, “unit”: “g” }, { “name”: “unsalted butter”, “quantity”: 113, “unit”: “g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: 1, “unit”: “teaspoon” }, { “name”: “kosher salt”, “quantity”: ¾, “unit”: “teaspoon” }, { “name”: “neutral oil”, “quantity”: 80, “unit”: “ml” }, { “name”: “all-purpose flour”, “quantity”: 190, “unit”: “g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons”, “unit”: “g” } ] }\n\n\nJust providing the examples seems to work remarkably well. But I found it useful to also include a description of what the examples are trying to accomplish. I’m not sure if this helps the LLM or not, but it certainly makes it easier for me to understand the organisation and check that I’ve covered the key pieces I’m interested in.\n\ninstruct_weight = \"\"\"\n * If an ingredient has both weight and volume, extract only the weight:\n\n ¾ cup (150g) dark brown sugar\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\"}\n ]\n\n* If an ingredient only lists a volume, extract that.\n\n 2 t ground cinnamon\n ⅓ cup (80ml) neutral oil\n [\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\"},\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\"}\n ]\n\"\"\"\n\nThis structure also allows me to give the LLMs a hint about how I want multiple ingredients to be stored, i.e. as an JSON array.\nI then iterated on the prompt, looking at the results from different recipes to get a sense of what the LLM was getting wrong. Much of this felt like I was iterating on my own understanding of the problem as I didn’t start by knowing exactly how I wanted the data. For example, when I started out I didn’t really think about all the various ways that ingredients are specified. For later analysis, I always want quantities to be number, even if they were originally fractions, or the if the units aren’t precise (like a pinch). It made me to realise that some ingredients are unitless.\n\ninstruct_unit = \"\"\"\n* If the unit uses a fraction, convert it to a decimal.\n\n ⅓ cup sugar\n ½ teaspoon salt\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 0.33, \"unit\": \"cup\"},\n {\"name\": \"salt\", \"quantity\": 0.5, \"unit\": \"teaspoon\"}\n ]\n\n* Quantities are always numbers\n\n pinch of kosher salt\n [\n {\"name\": \"kosher salt\", \"quantity\": 1, \"unit\": \"pinch\"}\n ]\n\n* Some ingredients don't have a unit.\n 2 eggs\n 1 lime\n 1 apple\n [\n {\"name\": \"egg\", \"quantity\": 2},\n {\"name\": \"lime\", \"quantity\": 1},\n {\"name\", \"apple\", \"quantity\": 1}\n ]\n\"\"\"\n\nYou might want to take a look at the full prompt to see what I ended up with.\n\n\nStructured data\nNow that I’ve iterated to get a data structure I like, it seems useful to formalise it and tell the LLM exactly what I’m looking for when dealing with structured data. This guarantees that the LLM will only return JSON, that the JSON will have the fields that you expect, and that chatlas will convert it into an Python data structure for you.\n\nfrom pydantic import BaseModel, Field\n\nclass Ingredient(BaseModel):\n \"Ingredient name\"\n name: str = Field(description=\"Ingredient name\")\n quantity: float\n unit: str | None = Field(description=\"Unit of measurement\")\n\nclass Ingredients(BaseModel):\n items: list[Ingredient]\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight\nchat.extract_data(ingredients, data_model=Ingredients)\n\n{'items': [{'name': 'dark brown sugar', 'quantity': 150, 'unit': 'g'},\n {'name': 'large eggs', 'quantity': 2, 'unit': 'count'},\n {'name': 'sour cream', 'quantity': 165, 'unit': 'g'},\n {'name': 'unsalted butter', 'quantity': 113, 'unit': 'g'},\n {'name': 'vanilla extract', 'quantity': 1, 'unit': 'teaspoon'},\n {'name': 'kosher salt', 'quantity': 0.75, 'unit': 'teaspoon'},\n {'name': 'neutral oil', 'quantity': 80, 'unit': 'ml'},\n {'name': 'all-purpose flour', 'quantity': 190, 'unit': 'g'},\n {'name': 'sugar', 'quantity': 150, 'unit': 'g'}]}\n\n\n\n\nCapturing raw input\nOne thing that I’d do next time would also be to include the raw ingredient names in the output. This doesn’t make much difference in this simple example but it makes it much easier to align the input with the output and to start developing automated measures of how well my prompt is doing.\n\ninstruct_weight_input = \"\"\"\n * If an ingredient has both weight and volume, extract only the weight:\n\n ¾ cup (150g) dark brown sugar\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\", \"input\": \"¾ cup (150g) dark brown sugar\"}\n ]\n\n * If an ingredient only lists a volume, extract that.\n\n 2 t ground cinnamon\n ⅓ cup (80ml) neutral oil\n [\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\", \"input\": \"2 t ground cinnamon\"},\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\", \"input\": \"⅓ cup (80ml) neutral oil\"}\n ]\n\"\"\"\n\nI think this is particularly important if you’re working with even less structured text. For example, imagine you had this text:\n\nrecipe = \"\"\"\n In a large bowl, cream together one cup of softened unsalted butter and a\n quarter cup of white sugar until smooth. Beat in an egg and 1 teaspoon of\n vanilla extract. Gradually stir in 2 cups of all-purpose flour until the\n dough forms. Finally, fold in 1 cup of semisweet chocolate chips. Drop\n spoonfuls of dough onto an ungreased baking sheet and bake at 350°F (175°C)\n for 10-12 minutes, or until the edges are lightly browned. Let the cookies\n cool on the baking sheet for a few minutes before transferring to a wire\n rack to cool completely. Enjoy!\n\"\"\"\n\nIncluding the input text in the output makes it easier to see if it’s doing a good job:\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight_input\n_ = chat.chat(ingredients)\n\n\n\n\n\n{ “ingredients”: [ { “name”: “dark brown sugar”, “quantity”: 150, “unit”: “g” }, { “name”: “large eggs”, “quantity”: 2, “unit”: “count” }, { “name”: “sour cream”, “quantity”: 165, “unit”: “g” }, { “name”: “unsalted butter”, “quantity”: 113, “unit”: “g”, “state”: “melted” }, { “name”: “vanilla extract”, “quantity”: 1, “unit”: “teaspoon” }, { “name”: “kosher salt”, “quantity”: 0.75, “unit”: “teaspoon” }, { “name”: “neutral oil”, “quantity”: 80, “unit”: “ml” }, { “name”: “all-purpose flour”, “quantity”: 190, “unit”: “g” }, { “name”: “sugar”, “quantity”: “150g plus 1½ teaspoons”, “unit”: “g” } ] }\n\n\nWhen I ran it while writing this vignette, it seemed to be working out the weight of the ingredients specified in volume, even though the prompt specifically asks it not to. This may suggest I need to broaden my examples." + "text": "Structured data\nProviding a rich set of examples is a great way to encourage the output to produce exactly what you want. This is known as multi-shot prompting. Below we’ll work through a prompt that I designed to extract structured data from recipes, but the same ideas apply in many other situations.\n\nGetting started\nMy overall goal is to turn a list of ingredients, like the following, into a nicely structured JSON that I can then analyse in Python (e.g. compute the total weight, scale the recipe up or down, or convert the units from volumes to weights).\n\ningredients = \"\"\"\n ¾ cup (150g) dark brown sugar\n 2 large eggs\n ¾ cup (165g) sour cream\n ½ cup (113g) unsalted butter, melted\n 1 teaspoon vanilla extract\n ¾ teaspoon kosher salt\n ⅓ cup (80ml) neutral oil\n 1½ cups (190g) all-purpose flour\n 150g plus 1½ teaspoons sugar\n\"\"\"\nchat = ChatOpenAI(model=\"gpt-4o-mini\")\n\n(This isn’t the ingredient list for a real recipe but it includes a sampling of styles that I encountered in my project.)\nIf you don’t have strong feelings about what the data structure should look like, you can start with a very loose prompt and see what you get back. I find this a useful pattern for underspecified problems where the heavy lifting lies with precisely defining the problem you want to solve. Seeing the LLM’s attempt to create a data structure gives me something to react to, rather than having to start from a blank page.\n\ninstruct_json = \"\"\"\n You're an expert baker who also loves JSON. I am going to give you a list of\n ingredients and your job is to return nicely structured JSON. Just return the\n JSON and no other commentary.\n\"\"\"\nchat.system_prompt = instruct_json\n_ = chat.chat(ingredients)\n\n\n\n\n\n{\n \"ingredients\": [\n {\n \"name\": \"dark brown sugar\",\n \"amount\": \"¾ cup\",\n \"weightInGrams\": 150\n },\n {\n \"name\": \"eggs\",\n \"amount\": \"2 large\"\n },\n {\n \"name\": \"sour cream\",\n \"amount\": \"¾ cup\",\n \"weightInGrams\": 165\n },\n {\n \"name\": \"unsalted butter\",\n \"amount\": \"½ cup\",\n \"weightInGrams\": 113,\n \"state\": \"melted\"\n },\n {\n \"name\": \"vanilla extract\",\n \"amount\": \"1 teaspoon\"\n },\n {\n \"name\": \"kosher salt\",\n \"amount\": \"¾ teaspoon\"\n },\n {\n \"name\": \"neutral oil\",\n \"amount\": \"⅓ cup\",\n \"volumeInMilliliters\": 80\n },\n {\n \"name\": \"all-purpose flour\",\n \"amount\": \"1½ cups\",\n \"weightInGrams\": 190\n },\n {\n \"name\": \"sugar\",\n \"amount\": \"150g plus 1½ teaspoons\",\n \"weightInGrams\": 150\n }\n ]\n}\n\n\n(I don’t know if the additional colour, “You’re an expert baker who also loves JSON”, does anything, but I like to think this helps the LLM get into the right mindset of a very nerdy baker.)\n\n\nProvide examples\nThis isn’t a bad start, but I prefer to cook with weight and I only want to see volumes if weight isn’t available so I provide a couple of examples of what I’m looking for. I was pleasantly suprised that I can provide the input and output examples in such a loose format.\n\ninstruct_weight = \"\"\"\n Here are some examples of the sort of output I'm looking for:\n\n ¾ cup (150g) dark brown sugar\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\"}\n\n ⅓ cup (80ml) neutral oil\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\"}\n\n 2 t ground cinnamon\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\"}\n\"\"\"\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight\n_ = chat.chat(ingredients)\n\n\n\n\n\n{\n \"ingredients\": [\n {\n \"name\": \"dark brown sugar\",\n \"quantity\": 150,\n \"unit\": \"g\"\n },\n {\n \"name\": \"large eggs\",\n \"quantity\": 2,\n \"unit\": \"count\"\n },\n {\n \"name\": \"sour cream\",\n \"quantity\": 165,\n \"unit\": \"g\"\n },\n {\n \"name\": \"unsalted butter\",\n \"quantity\": 113,\n \"unit\": \"g\",\n \"state\": \"melted\"\n },\n {\n \"name\": \"vanilla extract\",\n \"quantity\": 1,\n \"unit\": \"teaspoon\"\n },\n {\n \"name\": \"kosher salt\",\n \"quantity\": 0.75,\n \"unit\": \"teaspoon\"\n },\n {\n \"name\": \"neutral oil\",\n \"quantity\": 80,\n \"unit\": \"ml\"\n },\n {\n \"name\": \"all-purpose flour\",\n \"quantity\": 190,\n \"unit\": \"g\"\n },\n {\n \"name\": \"sugar\",\n \"quantity\": 150,\n \"unit\": \"g\",\n \"additional\": \"plus 1½ teaspoons\"\n }\n ]\n}\n\n\nJust providing the examples seems to work remarkably well. But I found it useful to also include a description of what the examples are trying to accomplish. I’m not sure if this helps the LLM or not, but it certainly makes it easier for me to understand the organisation and check that I’ve covered the key pieces I’m interested in.\n\ninstruct_weight = \"\"\"\n * If an ingredient has both weight and volume, extract only the weight:\n\n ¾ cup (150g) dark brown sugar\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\"}\n ]\n\n* If an ingredient only lists a volume, extract that.\n\n 2 t ground cinnamon\n ⅓ cup (80ml) neutral oil\n [\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\"},\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\"}\n ]\n\"\"\"\n\nThis structure also allows me to give the LLMs a hint about how I want multiple ingredients to be stored, i.e. as an JSON array.\nI then iterated on the prompt, looking at the results from different recipes to get a sense of what the LLM was getting wrong. Much of this felt like I was iterating on my own understanding of the problem as I didn’t start by knowing exactly how I wanted the data. For example, when I started out I didn’t really think about all the various ways that ingredients are specified. For later analysis, I always want quantities to be number, even if they were originally fractions, or the if the units aren’t precise (like a pinch). It made me to realise that some ingredients are unitless.\n\ninstruct_unit = \"\"\"\n* If the unit uses a fraction, convert it to a decimal.\n\n ⅓ cup sugar\n ½ teaspoon salt\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 0.33, \"unit\": \"cup\"},\n {\"name\": \"salt\", \"quantity\": 0.5, \"unit\": \"teaspoon\"}\n ]\n\n* Quantities are always numbers\n\n pinch of kosher salt\n [\n {\"name\": \"kosher salt\", \"quantity\": 1, \"unit\": \"pinch\"}\n ]\n\n* Some ingredients don't have a unit.\n 2 eggs\n 1 lime\n 1 apple\n [\n {\"name\": \"egg\", \"quantity\": 2},\n {\"name\": \"lime\", \"quantity\": 1},\n {\"name\", \"apple\", \"quantity\": 1}\n ]\n\"\"\"\n\nYou might want to take a look at the full prompt to see what I ended up with.\n\n\nStructured data\nNow that I’ve iterated to get a data structure I like, it seems useful to formalise it and tell the LLM exactly what I’m looking for when dealing with structured data. This guarantees that the LLM will only return JSON, that the JSON will have the fields that you expect, and that chatlas will convert it into an Python data structure for you.\n\nfrom pydantic import BaseModel, Field\n\nclass Ingredient(BaseModel):\n \"Ingredient name\"\n name: str = Field(description=\"Ingredient name\")\n quantity: float\n unit: str | None = Field(description=\"Unit of measurement\")\n\nclass Ingredients(BaseModel):\n items: list[Ingredient]\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight\nchat.extract_data(ingredients, data_model=Ingredients)\n\n{'items': [{'name': 'dark brown sugar', 'quantity': 150, 'unit': 'g'},\n {'name': 'eggs', 'quantity': 2, 'unit': 'large'},\n {'name': 'sour cream', 'quantity': 165, 'unit': 'g'},\n {'name': 'unsalted butter', 'quantity': 113, 'unit': 'g'},\n {'name': 'vanilla extract', 'quantity': 1, 'unit': 'teaspoon'},\n {'name': 'kosher salt', 'quantity': 0.75, 'unit': 'teaspoon'},\n {'name': 'neutral oil', 'quantity': 80, 'unit': 'ml'},\n {'name': 'all-purpose flour', 'quantity': 190, 'unit': 'g'},\n {'name': 'sugar', 'quantity': 150, 'unit': 'g'}]}\n\n\n\n\nCapturing raw input\nOne thing that I’d do next time would also be to include the raw ingredient names in the output. This doesn’t make much difference in this simple example but it makes it much easier to align the input with the output and to start developing automated measures of how well my prompt is doing.\n\ninstruct_weight_input = \"\"\"\n * If an ingredient has both weight and volume, extract only the weight:\n\n ¾ cup (150g) dark brown sugar\n [\n {\"name\": \"dark brown sugar\", \"quantity\": 150, \"unit\": \"g\", \"input\": \"¾ cup (150g) dark brown sugar\"}\n ]\n\n * If an ingredient only lists a volume, extract that.\n\n 2 t ground cinnamon\n ⅓ cup (80ml) neutral oil\n [\n {\"name\": \"ground cinnamon\", \"quantity\": 2, \"unit\": \"teaspoon\", \"input\": \"2 t ground cinnamon\"},\n {\"name\": \"neutral oil\", \"quantity\": 80, \"unit\": \"ml\", \"input\": \"⅓ cup (80ml) neutral oil\"}\n ]\n\"\"\"\n\nI think this is particularly important if you’re working with even less structured text. For example, imagine you had this text:\n\nrecipe = \"\"\"\n In a large bowl, cream together one cup of softened unsalted butter and a\n quarter cup of white sugar until smooth. Beat in an egg and 1 teaspoon of\n vanilla extract. Gradually stir in 2 cups of all-purpose flour until the\n dough forms. Finally, fold in 1 cup of semisweet chocolate chips. Drop\n spoonfuls of dough onto an ungreased baking sheet and bake at 350°F (175°C)\n for 10-12 minutes, or until the edges are lightly browned. Let the cookies\n cool on the baking sheet for a few minutes before transferring to a wire\n rack to cool completely. Enjoy!\n\"\"\"\n\nIncluding the input text in the output makes it easier to see if it’s doing a good job:\n\nchat.system_prompt = instruct_json + \"\\n\" + instruct_weight_input\n_ = chat.chat(ingredients)\n\n\n\n\n\n{\n \"ingredients\": [\n {\n \"name\": \"dark brown sugar\",\n \"quantity\": 150,\n \"unit\": \"g\"\n },\n {\n \"name\": \"eggs\",\n \"quantity\": 2,\n \"unit\": \"large\"\n },\n {\n \"name\": \"sour cream\",\n \"quantity\": 165,\n \"unit\": \"g\"\n },\n {\n \"name\": \"unsalted butter\",\n \"quantity\": 113,\n \"unit\": \"g\",\n \"state\": \"melted\"\n },\n {\n \"name\": \"vanilla extract\",\n \"quantity\": 1,\n \"unit\": \"teaspoon\"\n },\n {\n \"name\": \"kosher salt\",\n \"quantity\": 0.75,\n \"unit\": \"teaspoon\"\n },\n {\n \"name\": \"neutral oil\",\n \"quantity\": 80,\n \"unit\": \"ml\"\n },\n {\n \"name\": \"all-purpose flour\",\n \"quantity\": 190,\n \"unit\": \"g\"\n },\n {\n \"name\": \"sugar\",\n \"quantity\": 150,\n \"unit\": \"g\",\n \"additional\": \"plus 1½ teaspoons\"\n }\n ]\n}\n\n\nWhen I ran it while writing this vignette, it seemed to be working out the weight of the ingredients specified in volume, even though the prompt specifically asks it not to. This may suggest I need to broaden my examples." }, { "objectID": "prompt-design.html#token-usage", "href": "prompt-design.html#token-usage", "title": "Prompt design", "section": "Token usage", - "text": "Token usage\n\nfrom chatlas import token_usage\ntoken_usage()\n\n[{'name': 'Anthropic', 'input': 6504, 'output': 1270},\n {'name': 'OpenAI', 'input': 2909, 'output': 1043}]" + "text": "Token usage\n\nfrom chatlas import token_usage\ntoken_usage()\n\n[{'name': 'Anthropic', 'input': 5755, 'output': 1114},\n {'name': 'OpenAI', 'input': 3121, 'output': 1089}]" }, { - "objectID": "tool-calling.html", - "href": "tool-calling.html", - "title": "Introduction", + "objectID": "structured-data.html", + "href": "structured-data.html", + "title": "Structured data", "section": "", - "text": "One of the most interesting aspects of modern chat models is their ability to make use of external tools that are defined by the caller.\nWhen making a chat request to the chat model, the caller advertises one or more tools (defined by their function name, description, and a list of expected arguments), and the chat model can choose to respond with one or more “tool calls”. These tool calls are requests from the chat model to the caller to execute the function with the given arguments; the caller is expected to execute the functions and “return” the results by submitting another chat request with the conversation so far, plus the results. The chat model can then use those results in formulating its response, or, it may decide to make additional tool calls.\nNote that the chat model does not directly execute any external tools! It only makes requests for the caller to execute them. It’s easy to think that tool calling might work like this:\n\n\n\nDiagram showing showing the wrong mental model of tool calls: a user initiates a request that flows to the assistant, which then runs the code, and returns the result back to the user.”\n\n\nBut in fact it works like this:\n\n\n\nDiagram showing the correct mental model for tool calls: a user sends a request that needs a tool call, the assistant request that the user’s runs that tool, returns the result to the assistant, which uses it to generate the final answer.\n\n\nThe value that the chat model brings is not in helping with execution, but with knowing when it makes sense to call a tool, what values to pass as arguments, and how to use the results in formulating its response.\n\nfrom chatlas import ChatOpenAI\n\n\nMotivating example\nLet’s take a look at an example where we really need an external tool. Chat models generally do not have access to “real-time” information, such as current events, weather, etc. Let’s see what happens when we ask the chat model about the weather in a specific location:\n\nchat = ChatOpenAI(model=\"gpt-4o-mini\")\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\nI’m unable to provide real-time weather updates or current local conditions. I recommend checking a weather website or app for the latest information on the weather in Duluth, MN.\n\n\nFortunately, the model is smart enough to know that it doesn’t have access to real-time information, and it doesn’t try to make up an answer. However, we can help it out by providing a tool that can fetch the weather for a given location.\n\n\nDefining a tool function\nAt it turns out, LLMs are pretty good at figuring out ‘structure’ like latitude and longitude from ‘unstructured’ things like a location name. So we can write a tool function that takes a latitude and longitude and returns the current temperature at that location. Here’s an example of how you might write such a function using the Open-Meteo API:\n\nimport requests\n\ndef get_current_temperature(latitude: float, longitude: float):\n \"\"\"\n Get the current weather given a latitude and longitude.\n\n Parameters\n ----------\n latitude\n The latitude of the location.\n longitude\n The longitude of the location.\n \"\"\"\n lat_lng = f\"latitude={latitude}&longitude={longitude}\"\n url = f\"https://api.open-meteo.com/v1/forecast?{lat_lng}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m\"\n response = requests.get(url)\n json = response.json()\n return json[\"current\"]\n\nNote that we’ve gone through the trouble of adding the following to our function:\n\nType hints for function arguments\nA docstring that explains what the function does and what arguments it expects (as well as descriptions for the arguments themselves)\n\nProviding these hints and documentation is very important, as it helps the chat model understand how to use your tool correctly!\nLet’s test it:\n\nget_current_temperature(46.7867, -92.1005)\n\n{'time': '2024-12-13T22:30',\n 'interval': 900,\n 'temperature_2m': -11.3,\n 'wind_speed_10m': 8.7}\n\n\n\n\nUsing the tool\nIn order for the LLM to make use of our tool, we need to register it with the chat object. This is done by calling the register_tool method on the chat object.\n\nchat.register_tool(get_current_temperature)\n\nNow let’s retry our original question:\n\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\n\nToday’s weather in Duluth, MN, shows a temperature of -11.2°C. The wind speed is around 8.7 km/h. Make sure to dress warmly if you’re heading outside!\n\n\nThat’s correct! Without any further guidance, the chat model decided to call our tool function and successfully used its result in formulating its response.\nThis tool example was extremely simple, but you can imagine doing much more interesting things from tool functions: calling APIs, reading from or writing to a database, kicking off a complex simulation, or even calling a complementary GenAI model (like an image generator). Or if you are using chatlas in a Shiny app, you could use tools to set reactive values, setting off a chain of reactive updates. This is precisely what the sidebot dashboard does to allow for an AI assisted “drill-down” into the data.\n\n\nTrouble-shooting\nWhen the execution of a tool function fails, chatlas sends the exception message back to the chat model. This can be useful for gracefully handling errors in the chat model. However, this can also lead to confusion as to why a response did not come back as expected. If you encounter such a situation, you can set echo=\"all\" in the chat.chat() method to see the full conversation, including tool calls and their results.\n\ndef get_current_temperature(latitude: float, longitude: float):\n \"Get the current weather given a latitude and longitude.\"\n raise ValueError(\"Failed to get current temperature\")\n\nchat.register_tool(get_current_temperature)\n\n_ = chat.chat(\"What's the weather like today in Duluth, MN?\")\n\n\n\n\n\n\nI am currently unable to retrieve the weather information. However, you can check a weather website or app for the latest updates on the weather in Duluth, MN.\n\n\n\n\nTool limitations\nRemember that tool arguments come from the chat model, and tool results are returned to the chat model. That means that only simple, JSON-compatible data types can be used as inputs and outputs. It’s highly recommended that you stick to basic types for each function parameter (e.g. str, float/int, bool, None, list, tuple, dict). And you can forget about using functions, classes, external pointers, and other complex (i.e., non-serializable) Python objects as arguments or return values. Returning data frames seems to work OK (as long as you return the JSON representation – .to_json()), although be careful not to return too much data, as it all counts as tokens (i.e., they count against your context window limit and also cost you money)." + "text": "When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like. This will generally work well most of the time, but there’s no guarantee that you’ll actually get the exact format that you want. In particular, if you’re trying to get JSON, find that it’s typically surrounded in ```json, and you’ll occassionally get text that isn’t actually valid JSON. To avoid these challenges you can use a recent LLM feature: structured data (aka structured output). With structured data, you supply a type specification that exactly defines the object structure that you want and the LLM will guarantee that’s what you get back.\nimport json\nimport pandas as pd\nfrom chatlas import ChatOpenAI\nfrom pydantic import BaseModel, Field" }, { - "objectID": "index.html", - "href": "index.html", - "title": "chatlas", - "section": "", - "text": "chatlas provides a simple and unified interface across large language model (llm) providers in Python. It abstracts away complexity from common tasks like streaming chat interfaces, tool calling, structured output, and much more. chatlas helps you prototype faster without painting you into a corner; for example, switching providers is as easy as changing one line of code, but provider specific features are still accessible when needed. Developer experience is also a key focus of chatlas: typing support, rich console output, and built-in tooling are all included.\n(Looking for something similar to chatlas, but in R? Check out elmer!)\n\n\nInstall the latest stable release from PyPI:\npip install -U chatlas\nOr, install the latest development version from GitHub:\npip install -U git+https://github.com/posit-dev/chatlas\n\n\n\nchatlas supports a variety of model providers. See the API reference for more details (like managing credentials) on each provider.\n\nAnthropic (Claude): ChatAnthropic().\nGitHub model marketplace: ChatGithub().\nGoogle (Gemini): ChatGoogle().\nGroq: ChatGroq().\nOllama local models: ChatOllama().\nOpenAI: ChatOpenAI().\nperplexity.ai: ChatPerplexity().\n\nIt also supports the following enterprise cloud providers:\n\nAWS Bedrock: ChatBedrockAnthropic().\nAzure OpenAI: ChatAzureOpenAI().\n\nTo use a model provider that isn’t listed here, you have two options:\n\nIf the model is OpenAI compatible, use ChatOpenAI() with the appropriate base_url and api_key (see ChatGithub for a reference).\nIf you’re motivated, implement a new provider by subclassing Provider and implementing the required methods.\n\n\n\n\nIf you’re using chatlas inside your organisation, you’ll be limited to what your org allows, which is likely to be one provided by a big cloud provider (e.g. ChatAzureOpenAI() and ChatBedrockAnthropic()). If you’re using chatlas for your own personal exploration, you have a lot more freedom so we have a few recommendations to help you get started:\n\nChatOpenAI() or ChatAnthropic() are both good places to start. ChatOpenAI() defaults to GPT-4o, but you can use model = \"gpt-4o-mini\" for a cheaper lower-quality model, or model = \"o1-mini\" for more complex reasoning. ChatAnthropic() is similarly good; it defaults to Claude 3.5 Sonnet which we have found to be particularly good at writing code.\nChatGoogle() is great for large prompts, because it has a much larger context window than other models. It allows up to 1 million tokens, compared to Claude 3.5 Sonnet’s 200k and GPT-4o’s 128k.\nChatOllama(), which uses Ollama, allows you to run models on your own computer. The biggest models you can run locally aren’t as good as the state of the art hosted models, but they also don’t share your data and and are effectively free.\n\n\n\n\nYou can chat via chatlas in several different ways, depending on whether you are working interactively or programmatically. They all start with creating a new chat object:\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(\n model = \"gpt-4o\",\n system_prompt = \"You are a friendly but terse assistant.\",\n)\n\n\nFrom a chat instance, it’s simple to start a web-based or terminal-based chat console, which is great for testing the capabilities of the model. In either case, responses stream in real-time, and context is preserved across turns.\nchat.app()\n\n\n\nOr, if you prefer to work from the terminal:\nchat.console()\nEntering chat console. Press Ctrl+C to quit.\n\n?> Who created Python?\n\nPython was created by Guido van Rossum. He began development in the late 1980s and released the first version in 1991. \n\n?> Where did he develop it?\n\nGuido van Rossum developed Python while working at Centrum Wiskunde & Informatica (CWI) in the Netherlands. \n\n\n\nFor a more programmatic approach, you can use the .chat() method to ask a question and get a response. By default, the response prints to a rich console as it streams in:\nchat.chat(\"What preceding languages most influenced Python?\")\nPython was primarily influenced by ABC, with additional inspiration from C,\nModula-3, and various other languages.\nTo ask a question about an image, pass one or more additional input arguments using content_image_file() and/or content_image_url():\nfrom chatlas import content_image_url\n\nchat.chat(\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n \"Can you explain this logo?\"\n)\nThe Python logo features two intertwined snakes in yellow and blue,\nrepresenting the Python programming language. The design symbolizes...\nTo get the full response as a string, use the built-in str() function. Optionally, you can also suppress the rich console output by setting echo=\"none\":\nresponse = chat.chat(\"Who is Posit?\", echo=\"none\")\nprint(str(response))\nAs we’ll see in later articles, echo=\"all\" can also be useful for debugging, as it shows additional information, such as tool calls.\n\n\n\nIf you want to do something with the response in real-time (i.e., as it arrives in chunks), use the .stream() method. This method returns an iterator that yields each chunk of the response as it arrives:\nresponse = chat.stream(\"Who is Posit?\")\nfor chunk in response:\n print(chunk, end=\"\")\nThe .stream() method can also be useful if you’re building a chatbot or other programs that needs to display responses as they arrive.\n\n\n\nTool calling is as simple as passing a function with type hints and docstring to .register_tool().\nimport sys\n\ndef get_current_python_version() -> str:\n \"\"\"Get the current version of Python.\"\"\"\n return sys.version\n\nchat.register_tool(get_current_python_version)\nchat.chat(\"What's the current version of Python?\")\nThe current version of Python is 3.13.\nLearn more in the tool calling article\n\n\n\nStructured data (i.e., structured output) is as simple as passing a pydantic model to .extract_data().\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n name: str\n age: int\n\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n{'name': 'Susan', 'age': 13}\nLearn more in the structured data article\n\n\n\nEasily get a full markdown or HTML export of a conversation:\nchat.export(\"index.html\", title=\"Python Q&A\")\nIf the export doesn’t have all the information you need, you can also access the full conversation history via the .get_turns() method:\nchat.get_turns()\nAnd, if the conversation is too long, you can specify which turns to include:\nchat.export(\"index.html\", turns=chat.get_turns()[-5:])\n\n\n\nchat methods tend to be synchronous by default, but you can use the async flavor by appending _async to the method name:\nimport asyncio\n\nasync def main():\n await chat.chat_async(\"What is the capital of France?\")\n\nasyncio.run(main())\n\n\n\nchatlas has full typing support, meaning that, among other things, autocompletion just works in your favorite editor:\n\n\n\n\n\n\nSometimes things like token limits, tool errors, or other issues can cause problems that are hard to diagnose. In these cases, the echo=\"all\" option is helpful for getting more information about what’s going on under the hood.\nchat.chat(\"What is the capital of France?\", echo=\"all\")\nThis shows important information like tool call results, finish reasons, and more.\nIf the problem isn’t self-evident, you can also reach into the .get_last_turn(), which contains the full response object, with full details about the completion.\n\n\n\nFor monitoring issues in a production (or otherwise non-interactive) environment, you may want to enabling logging. Also, since chatlas builds on top of packages like anthropic and openai, you can also enable their debug logging to get lower-level information, like HTTP requests and response codes.\n$ export CHATLAS_LOG=info\n$ export OPENAI_LOG=info\n$ export ANTHROPIC_LOG=info\n\n\n\nIf you’re new to world LLMs, you might want to read the Get Started guide, which covers some basic concepts and terminology.\nOnce you’re comfortable with the basics, you can explore more in-depth topics like prompt design or the API reference." + "objectID": "structured-data.html#structured-data-basics", + "href": "structured-data.html#structured-data-basics", + "title": "Structured data", + "section": "Structured data basics", + "text": "Structured data basics\nTo extract structured data you call the .extract_data() method instead of the .chat() method. You’ll also need to define a type specification that describes the structure of the data that you want (more on that shortly). Here’s a simple example that extracts two specific values from a string:\n\nclass Person(BaseModel):\n name: str\n age: int\n\n\nchat = ChatOpenAI()\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n\n{'name': 'Susan', 'age': 13}\n\n\nThe same basic idea works with images too:\n\nfrom chatlas import content_image_url\n\nclass Image(BaseModel):\n primary_shape: str\n primary_colour: str\n\nchat.extract_data(\n content_image_url(\"https://www.r-project.org/Rlogo.png\"),\n data_model=Image,\n)\n\n{'primary_shape': \"letter 'R' with an oval\", 'primary_colour': 'blue and grey'}" }, { - "objectID": "index.html#install", - "href": "index.html#install", - "title": "chatlas", - "section": "", - "text": "Install the latest stable release from PyPI:\npip install -U chatlas\nOr, install the latest development version from GitHub:\npip install -U git+https://github.com/posit-dev/chatlas" + "objectID": "structured-data.html#data-types-basics", + "href": "structured-data.html#data-types-basics", + "title": "Structured data", + "section": "Data types basics", + "text": "Data types basics\nTo define your desired type specification (also known as a schema), you use a pydantic model.\nIn addition to the model definition with field names and types, you may also want to provide the LLM with an additional context about what each field/model represents. In this case, include a Field(description=\"...\") for each field, and a docstring for each model. This is a good place to ask nicely for other attributes you’ll like the value to possess (e.g. minimum or maximum values, date formats, …). You aren’t guaranteed that these requests will be honoured, but the LLM will usually make a best effort to do so.\n\nclass Person(BaseModel):\n \"\"\"A person\"\"\"\n\n name: str = Field(description=\"Name\")\n\n age: int = Field(description=\"Age, in years\")\n\n hobbies: list[str] = Field(\n description=\"List of hobbies. Should be exclusive and brief.\"\n )\n\nNow we’ll dive into some examples before coming back to talk more data types details." }, { - "objectID": "index.html#model-providers", - "href": "index.html#model-providers", - "title": "chatlas", - "section": "", - "text": "chatlas supports a variety of model providers. See the API reference for more details (like managing credentials) on each provider.\n\nAnthropic (Claude): ChatAnthropic().\nGitHub model marketplace: ChatGithub().\nGoogle (Gemini): ChatGoogle().\nGroq: ChatGroq().\nOllama local models: ChatOllama().\nOpenAI: ChatOpenAI().\nperplexity.ai: ChatPerplexity().\n\nIt also supports the following enterprise cloud providers:\n\nAWS Bedrock: ChatBedrockAnthropic().\nAzure OpenAI: ChatAzureOpenAI().\n\nTo use a model provider that isn’t listed here, you have two options:\n\nIf the model is OpenAI compatible, use ChatOpenAI() with the appropriate base_url and api_key (see ChatGithub for a reference).\nIf you’re motivated, implement a new provider by subclassing Provider and implementing the required methods." + "objectID": "structured-data.html#examples", + "href": "structured-data.html#examples", + "title": "Structured data", + "section": "Examples", + "text": "Examples\nThe following examples are closely inspired by the Claude documentation and hint at some of the ways you can use structured data extraction.\n\nExample 1: Article summarisation\n\nwith open(\"examples/third-party-testing.txt\") as f:\n text = f.read()\n\n\nclass ArticleSummary(BaseModel):\n \"\"\"Summary of the article.\"\"\"\n\n author: str = Field(description=\"Name of the article author\")\n\n topics: list[str] = Field(\n description=\"Array of topics, e.g. ['tech', 'politics']. Should be as specific as possible, and can overlap.\"\n )\n\n summary: str = Field(description=\"Summary of the article. One or two paragraphs max\")\n\n coherence: int = Field(\n description=\"Coherence of the article's key points, 0-100 (inclusive)\"\n )\n\n persuasion: float = Field(\n description=\"Article's persuasion score, 0.0-1.0 (inclusive)\"\n )\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=ArticleSummary)\nprint(json.dumps(data, indent=2))\n\n{\n \"author\": \"Anthropic Team\",\n \"topics\": [\n \"AI policy\",\n \"third-party testing\",\n \"regulation\",\n \"AI safety\"\n ],\n \"summary\": \"The article emphasizes the importance of implementing a third-party testing regime for AI systems, particularly large-scale generative models like Claude, ChatGPT, and Gemini. Given the transformative potential and risks of these AI systems, the authors argue for a comprehensive oversight framework involving industry, government, and academia. Current self-governance initiatives, like Anthropic's Responsible Scaling Policy, are seen as insufficient for industry-wide credibility. Therefore, creating broadly-trusted third-party testing and evaluation processes is crucial for validating AI safety, preventing misuse, and avoiding over-regulation. The authors advocate for initial experiments and government-backed testing infrastructures to iteratively develop an effective and fair system that minimizes accidents while ensuring competitiveness.\",\n \"coherence\": 90,\n \"persuasion\": 0.85\n}\n\n\n\n\nExample 2: Named entity recognition\n\ntext = \"John works at Google in New York. He met with Sarah, the CEO of Acme Inc., last week in San Francisco.\"\n\n\nclass NamedEntity(BaseModel):\n \"\"\"Named entity in the text.\"\"\"\n\n name: str = Field(description=\"The extracted entity name\")\n\n type_: str = Field(description=\"The entity type, e.g. 'person', 'location', 'organization'\")\n\n context: str = Field(description=\"The context in which the entity appears in the text.\")\n\n\nclass NamedEntities(BaseModel):\n \"\"\"Named entities in the text.\"\"\"\n\n entities: list[NamedEntity] = Field(description=\"Array of named entities\")\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=NamedEntities)\npd.DataFrame(data[\"entities\"])\n\n\n\n\n\n\n\n\nname\ntype_\ncontext\n\n\n\n\n0\nJohn\nperson\nJohn works at Google in New York.\n\n\n1\nGoogle\norganization\nJohn works at Google in New York.\n\n\n2\nNew York\nlocation\nJohn works at Google in New York.\n\n\n3\nSarah\nperson\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n4\nCEO\nposition\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n5\nAcme Inc.\norganization\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n6\nSan Francisco\nlocation\nHe met with Sarah, the CEO of Acme Inc., last ...\n\n\n\n\n\n\n\n\n\nExample 3: Sentiment analysis\n\ntext = \"The product was okay, but the customer service was terrible. I probably won't buy from them again.\"\n\nclass Sentiment(BaseModel):\n \"\"\"Extract the sentiment scores of a given text. Sentiment scores should sum to 1.\"\"\"\n\n positive_score: float = Field(\n description=\"Positive sentiment score, ranging from 0.0 to 1.0\"\n )\n\n negative_score: float = Field(\n description=\"Negative sentiment score, ranging from 0.0 to 1.0\"\n )\n\n neutral_score: float = Field(\n description=\"Neutral sentiment score, ranging from 0.0 to 1.0\"\n )\n\n\nchat = ChatOpenAI()\nchat.extract_data(text, data_model=Sentiment)\n\n{'positive_score': 0.15, 'negative_score': 0.7, 'neutral_score': 0.15}\n\n\nNote that we’ve asked nicely for the scores to sum 1, and they do in this example (at least when I ran the code), but it’s not guaranteed.\n\n\nExample 4: Text classification\n\nfrom typing import Literal\n\ntext = \"The new quantum computing breakthrough could revolutionize the tech industry.\"\n\n\nclass Classification(BaseModel):\n\n name: Literal[\n \"Politics\", \"Sports\", \"Technology\", \"Entertainment\", \"Business\", \"Other\"\n ] = Field(description=\"The category name\")\n\n score: float = Field(description=\"The classification score for the category, ranging from 0.0 to 1.0.\")\n\n\nclass Classifications(BaseModel):\n \"\"\"Array of classification results. The scores should sum to 1.\"\"\"\n\n classifications: list[Classification]\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(text, data_model=Classifications)\npd.DataFrame(data[\"classifications\"])\n\n\n\n\n\n\n\n\nname\nscore\n\n\n\n\n0\nTechnology\n0.70\n\n\n1\nBusiness\n0.15\n\n\n2\nOther\n0.15\n\n\n\n\n\n\n\n\n\nExample 5: Working with unknown keys\n\nfrom chatlas import ChatAnthropic\n\n\nclass Characteristics(BaseModel, extra=\"allow\"):\n \"\"\"All characteristics\"\"\"\n\n pass\n\n\nprompt = \"\"\"\n Given a description of a character, your task is to extract all the characteristics of that character.\n\n <description>\n The man is tall, with a beard and a scar on his left cheek. He has a deep voice and wears a black leather jacket.\n </description>\n\"\"\"\n\nchat = ChatAnthropic()\ndata = chat.extract_data(prompt, data_model=Characteristics)\nprint(json.dumps(data, indent=2))\n\n{\n \"physical_characteristics\": {\n \"height\": \"tall\",\n \"facial_features\": {\n \"beard\": true,\n \"scar\": {\n \"location\": \"left cheek\"\n }\n },\n \"voice\": \"deep\"\n },\n \"clothing\": {\n \"outerwear\": {\n \"type\": \"leather jacket\",\n \"color\": \"black\"\n }\n }\n}\n\n\nThis example only works with Claude, not GPT or Gemini, because only Claude supports adding arbitrary additional properties.\n\n\nExample 6: Extracting data from an image\nThis example comes from Dan Nguyen and you can see other interesting applications at that link. The goal is to extract structured data from this screenshot:\nThe goal is to extract structured data from this screenshot:\n\n\n\nA screenshot of schedule A: a table showing assets and “unearned” income\n\n\nEven without any descriptions, ChatGPT does pretty well:\n\nfrom chatlas import content_image_file\n\n\nclass Asset(BaseModel):\n assert_name: str\n owner: str\n location: str\n asset_value_low: int\n asset_value_high: int\n income_type: str\n income_low: int\n income_high: int\n tx_gt_1000: bool\n\n\nclass DisclosureReport(BaseModel):\n assets: list[Asset]\n\n\nchat = ChatOpenAI()\ndata = chat.extract_data(\n content_image_file(\"images/congressional-assets.png\"), data_model=DisclosureReport\n)\npd.DataFrame(data[\"assets\"])\n\n\n\n\n\n\n\n\nassert_name\nowner\nlocation\nasset_value_low\nasset_value_high\nincome_type\nincome_low\nincome_high\ntx_gt_1000\n\n\n\n\n0\n11 Zinfandel Lane - Home & Vineyard [RP]\nJT\nSt. Helena/Napa, CA, US\n5000001\n25000000\nGrape Sales\n100001\n1000000\nTrue\n\n\n1\n25 Point Lobos - Commercial Property [RP]\nSP\nSan Francisco/San Francisco, CA, US\n5000001\n25000000\nRent\n100001\n1000000\nTrue" }, { - "objectID": "index.html#model-choice", - "href": "index.html#model-choice", - "title": "chatlas", - "section": "", - "text": "If you’re using chatlas inside your organisation, you’ll be limited to what your org allows, which is likely to be one provided by a big cloud provider (e.g. ChatAzureOpenAI() and ChatBedrockAnthropic()). If you’re using chatlas for your own personal exploration, you have a lot more freedom so we have a few recommendations to help you get started:\n\nChatOpenAI() or ChatAnthropic() are both good places to start. ChatOpenAI() defaults to GPT-4o, but you can use model = \"gpt-4o-mini\" for a cheaper lower-quality model, or model = \"o1-mini\" for more complex reasoning. ChatAnthropic() is similarly good; it defaults to Claude 3.5 Sonnet which we have found to be particularly good at writing code.\nChatGoogle() is great for large prompts, because it has a much larger context window than other models. It allows up to 1 million tokens, compared to Claude 3.5 Sonnet’s 200k and GPT-4o’s 128k.\nChatOllama(), which uses Ollama, allows you to run models on your own computer. The biggest models you can run locally aren’t as good as the state of the art hosted models, but they also don’t share your data and and are effectively free." + "objectID": "structured-data.html#advanced-data-types", + "href": "structured-data.html#advanced-data-types", + "title": "Structured data", + "section": "Advanced data types", + "text": "Advanced data types\nNow that you’ve seen a few examples, it’s time to get into more specifics about data type declarations.\n\nRequired vs optional\nBy default, model fields are in a sense “required”, unless None is allowed in their type definition. Including None is a good idea if there’s any possibility of the input not containing the required fields as LLMs may hallucinate data in order to fulfill your spec.\nFor example, here the LLM hallucinates a date even though there isn’t one in the text:\n\nclass ArticleSpec(BaseModel):\n \"\"\"Information about an article written in markdown\"\"\"\n\n title: str = Field(description=\"Article title\")\n author: str = Field(description=\"Name of the author\")\n date: str = Field(description=\"Date written in YYYY-MM-DD format.\")\n\n\nprompt = \"\"\"\n Extract data from the following text:\n\n <text>\n # Structured Data\n By Hadley Wickham\n\n When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like.\n </text>\n\"\"\"\n\nchat = ChatOpenAI()\ndata = chat.extract_data(prompt, data_model=ArticleSpec)\nprint(json.dumps(data, indent=2))\n\n{\n \"title\": \"Structured Data\",\n \"author\": \"Hadley Wickham\",\n \"date\": \"2023-10-30\"\n}\n\n\nNote that I’ve used more of an explict prompt here. For this example, I found that this generated better results, and it’s a useful place to put additional instructions.\nIf let the LLM know that the fields are all optional, it’ll instead return None for the missing fields:\n\nclass ArticleSpec(BaseModel):\n \"\"\"Information about an article written in markdown\"\"\"\n\n title: str = Field(description=\"Article title\")\n author: str = Field(description=\"Name of the author\")\n date: str | None = Field(description=\"Date written in YYYY-MM-DD format.\")\n\n\ndata = chat.extract_data(prompt, data_model=ArticleSpec)\nprint(json.dumps(data, indent=2))\n\n{\n \"title\": \"Structured Data\",\n \"author\": \"Hadley Wickham\",\n \"date\": null\n}\n\n\n\n\nData frames\nIf you want to define a data frame like data_model, you might be tempted to create a model like this, where each field is a list of scalar values:\nclass Persons(BaseModel):\n name: list[str]\n age: list[int]\nThis however, is not quite right because there’s no way to specify that each field should have the same length. Instead you need to turn the data structure “inside out”, and instead create an array of objects:\nclass Person(BaseModel):\n name: str\n age: int\n\nclass Persons(BaseModel):\n persons: list[Person]\nIf you’re familiar with the terms between row-oriented and column-oriented data frames, this is the same idea." }, { - "objectID": "index.html#using-chatlas", - "href": "index.html#using-chatlas", - "title": "chatlas", - "section": "", - "text": "You can chat via chatlas in several different ways, depending on whether you are working interactively or programmatically. They all start with creating a new chat object:\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(\n model = \"gpt-4o\",\n system_prompt = \"You are a friendly but terse assistant.\",\n)\n\n\nFrom a chat instance, it’s simple to start a web-based or terminal-based chat console, which is great for testing the capabilities of the model. In either case, responses stream in real-time, and context is preserved across turns.\nchat.app()\n\n\n\nOr, if you prefer to work from the terminal:\nchat.console()\nEntering chat console. Press Ctrl+C to quit.\n\n?> Who created Python?\n\nPython was created by Guido van Rossum. He began development in the late 1980s and released the first version in 1991. \n\n?> Where did he develop it?\n\nGuido van Rossum developed Python while working at Centrum Wiskunde & Informatica (CWI) in the Netherlands. \n\n\n\nFor a more programmatic approach, you can use the .chat() method to ask a question and get a response. By default, the response prints to a rich console as it streams in:\nchat.chat(\"What preceding languages most influenced Python?\")\nPython was primarily influenced by ABC, with additional inspiration from C,\nModula-3, and various other languages.\nTo ask a question about an image, pass one or more additional input arguments using content_image_file() and/or content_image_url():\nfrom chatlas import content_image_url\n\nchat.chat(\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n \"Can you explain this logo?\"\n)\nThe Python logo features two intertwined snakes in yellow and blue,\nrepresenting the Python programming language. The design symbolizes...\nTo get the full response as a string, use the built-in str() function. Optionally, you can also suppress the rich console output by setting echo=\"none\":\nresponse = chat.chat(\"Who is Posit?\", echo=\"none\")\nprint(str(response))\nAs we’ll see in later articles, echo=\"all\" can also be useful for debugging, as it shows additional information, such as tool calls.\n\n\n\nIf you want to do something with the response in real-time (i.e., as it arrives in chunks), use the .stream() method. This method returns an iterator that yields each chunk of the response as it arrives:\nresponse = chat.stream(\"Who is Posit?\")\nfor chunk in response:\n print(chunk, end=\"\")\nThe .stream() method can also be useful if you’re building a chatbot or other programs that needs to display responses as they arrive.\n\n\n\nTool calling is as simple as passing a function with type hints and docstring to .register_tool().\nimport sys\n\ndef get_current_python_version() -> str:\n \"\"\"Get the current version of Python.\"\"\"\n return sys.version\n\nchat.register_tool(get_current_python_version)\nchat.chat(\"What's the current version of Python?\")\nThe current version of Python is 3.13.\nLearn more in the tool calling article\n\n\n\nStructured data (i.e., structured output) is as simple as passing a pydantic model to .extract_data().\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n name: str\n age: int\n\nchat.extract_data(\n \"My name is Susan and I'm 13 years old\", \n data_model=Person,\n)\n{'name': 'Susan', 'age': 13}\nLearn more in the structured data article\n\n\n\nEasily get a full markdown or HTML export of a conversation:\nchat.export(\"index.html\", title=\"Python Q&A\")\nIf the export doesn’t have all the information you need, you can also access the full conversation history via the .get_turns() method:\nchat.get_turns()\nAnd, if the conversation is too long, you can specify which turns to include:\nchat.export(\"index.html\", turns=chat.get_turns()[-5:])\n\n\n\nchat methods tend to be synchronous by default, but you can use the async flavor by appending _async to the method name:\nimport asyncio\n\nasync def main():\n await chat.chat_async(\"What is the capital of France?\")\n\nasyncio.run(main())\n\n\n\nchatlas has full typing support, meaning that, among other things, autocompletion just works in your favorite editor:\n\n\n\n\n\n\nSometimes things like token limits, tool errors, or other issues can cause problems that are hard to diagnose. In these cases, the echo=\"all\" option is helpful for getting more information about what’s going on under the hood.\nchat.chat(\"What is the capital of France?\", echo=\"all\")\nThis shows important information like tool call results, finish reasons, and more.\nIf the problem isn’t self-evident, you can also reach into the .get_last_turn(), which contains the full response object, with full details about the completion.\n\n\n\nFor monitoring issues in a production (or otherwise non-interactive) environment, you may want to enabling logging. Also, since chatlas builds on top of packages like anthropic and openai, you can also enable their debug logging to get lower-level information, like HTTP requests and response codes.\n$ export CHATLAS_LOG=info\n$ export OPENAI_LOG=info\n$ export ANTHROPIC_LOG=info\n\n\n\nIf you’re new to world LLMs, you might want to read the Get Started guide, which covers some basic concepts and terminology.\nOnce you’re comfortable with the basics, you can explore more in-depth topics like prompt design or the API reference." + "objectID": "structured-data.html#token-usage", + "href": "structured-data.html#token-usage", + "title": "Structured data", + "section": "Token usage", + "text": "Token usage\nBelow is a summary of the tokens used to create the output in this example.\n\nfrom chatlas import token_usage\ntoken_usage()\n\n[{'name': 'OpenAI', 'input': 6081, 'output': 642},\n {'name': 'Anthropic', 'input': 463, 'output': 139}]" }, { - "objectID": "get-started.html", - "href": "get-started.html", + "objectID": "web-apps.html", + "href": "web-apps.html", "title": "chatlas", "section": "", - "text": "chatlas makes it easy to access the wealth of large language models (LLMs) from Python. But what can you do with those models once you have access to them? This vignette will give you the basic vocabulary you need to use an LLM effectively and will show you some examples to ignite your creativity.\nIn this article we’ll mostly ignore how LLMs work, using them as convenient black boxes. If you want to get a sense of how they actually work, we recommend watching Jeremy Howard’s posit::conf(2023) keynote: A hacker’s guide to open source LLMs." - }, - { - "objectID": "get-started.html#vocabulary", - "href": "get-started.html#vocabulary", - "title": "chatlas", - "section": "Vocabulary", - "text": "Vocabulary\nWe’ll start by laying out the key vocab that you’ll need to understand LLMs. Unfortunately the vocab is all a little entangled: to understand one term you’ll often have to know a little about some of the others. So we’ll start with some simple definitions of the most important terms then iteratively go a little deeper.\nIt all starts with a prompt, which is the text (typically a question or a request) that you send to the LLM. This starts a conversation, a sequence of turns that alternate between user prompts and model responses. Inside the model, both the prompt and response are represented by a sequence of tokens, which represent either individual words or subcomponents of a word. The tokens are used to compute the cost of using a model and to measure the size of the context, the combination of the current prompt and any previous prompts and responses used to generate the next response.\nIt’s useful to make the distinction between providers and models. A provider is a web API that gives access to one or more models. The distinction is a bit subtle because providers are often synonymous with a model, like OpenAI and GPT, Anthropic and Claude, and Google and Gemini. But other providers, like Ollama, can host many different models, typically open source models like LLaMa and Mistral. Still other providers support both open and closed models, typically by partnering with a company that provides a popular closed model. For example, Azure OpenAI offers both open source models and OpenAI’s GPT, while AWS Bedrock offers both open source models and Anthropic’s Claude.\n\nWhat is a token?\nAn LLM is a model, and like all models needs some way to represent its inputs numerically. For LLMs, that means we need some way to convert words to numbers. This is the goal of the tokenizer. For example, using the GPT 4o tokenizer, the string “When was R created?” is converted to 5 tokens: 5958 (“When”), 673 (” was”), 460 (” R”), 5371 (” created”), 30 (“?”). As you can see, many simple strings can be represented by a single token. But more complex strings require multiple tokens. For example, the string “counterrevolutionary” requires 4 tokens: 32128 (“counter”), 264 (“re”), 9477 (“volution”), 815 (“ary”). (You can see how various strings are tokenized at http://tiktokenizer.vercel.app/).\nIt’s important to have a rough sense of how text is converted to tokens because tokens are used to determine the cost of a model and how much context can be used to predict the next response. On average an English word needs ~1.5 tokens so a page might require 375-400 tokens and a complete book might require 75,000 to 150,000 tokens. Other languages will typically require more tokens, because (in brief) LLMs are trained on data from the internet, which is primarily in English.\nLLMs are priced per million tokens. State of the art models (like GPT-4o or Claude 3.5 sonnet) cost $2-3 per million input tokens, and $10-15 per million output tokens. Cheaper models can cost much less, e.g. GPT-4o mini costs $0.15 per million input tokens and $0.60 per million output tokens. Even $10 of API credit will give you a lot of room for experimentation, particularly with cheaper models, and prices are likely to decline as model performance improves.\nTokens also used to measure the context window, which is how much text the LLM can use to generate the next response. As we’ll discuss shortly, the context length includes the full state of your conversation so far (both your prompts and the model’s responses), which means that cost grow rapidly with the number of conversational turns.\n\n\nWhat is a conversation?\nA conversation with an LLM takes place through a series of HTTP requests and responses: you send your question to the LLM as an HTTP request, and it sends back its reply as an HTTP response. In other words, a conversation consists of a sequence of a paired turns: a sent prompt and a returned response.\nIt’s important to note that a request includes not only the current user prompt, but every previous user prompt and model response. This means that:\n\nThe cost of a conversation grows quadratically with the number of turns: if you want to save money, keep your conversations short.\nEach response is affected by all previous prompts and responses. This can make a converstion get stuck in a local optimum, so it’s generally better to iterate by starting a new conversation with a better prompt rather than having a long back-and-forth.\nchatlas has full control over the conversational history. Because it’s chatlas’s responsibility to send the previous turns of the conversation, it’s possible to start a conversation with one model and finish it with another.\n\n\n\nWhat is a prompt?\nThe user prompt is the question that you send to the model. There are two other important prompts that underlie the user prompt:\n\nThe core system prompt, which is unchangeable, set by the model provider, and affects every conversation. You can see what these look like from Anthropic, who publishes their core system prompts.\nThe system prompt, which is set when you create a new conversation, and affects every response. It’s used to provide additional instructions to the model, shaping its responses to your needs. For example, you might use the system prompt to ask the model to always respond in Spanish or to write dependency-free base R code. You can also use the system prompt to provide the model with information it wouldn’t otherwise know, like the details of your database schema, or your preferred plotly theme and color palette.\n\nWhen you use a chat app like ChatGPT or claude.ai you can only iterate on the user prompt. But when you’re programming with LLMs, you’ll primarily iterate on the system prompt. For example, if you’re developing an app that helps a user write Python code, you’d work with the system prompt to ensure that user gets the style of code they want.\nWriting a good prompt, which is called prompt design, is key to effective use of LLMs. It is discussed in more detail in the prompt design article." + "text": "In the intro, we learned how the .app() method launches a web app with a simple chat interface, for example:\nThis is a great way to quickly test your model, but you’ll likely want to embed similar functionality into a larger web app. Here’s how you can do that we different web frameworks." }, { - "objectID": "get-started.html#example-uses", - "href": "get-started.html#example-uses", + "objectID": "web-apps.html#shiny", + "href": "web-apps.html#shiny", "title": "chatlas", - "section": "Example uses", - "text": "Example uses\nNow that you’ve got the basic vocab under your belt, I’m going to fire a bunch of interesting potential use cases at you. While there are special purpose tools that might solve these cases faster and/or cheaper, an LLM allows you to rapidly prototype a solution. This can be extremely valuable even if you end up using those more specialised tools in your final product.\nIn general, we recommend avoiding LLMs where accuracy is critical. That said, there are still many cases for their use. For example, even though they always requires some manual fiddling, you might save a bunch of time evern with an 80% correct solution. In fact, even a not-so-good solution can still be useful because it makes it easier to get started: it’s easier to react to something rather than to have to start from scratch with a blank page.\n\nChatbots\nA great place to start with chatlas and LLMs is to build a chatbot with a custom prompt. Chatbots are familiar interface and are easy to create via web application framework like Shiny or Streamlit. And there’s a surprising amount of value to creating a custom chatbot that has a prompt stuffed with useful knowledge. For example:\n\nHelp people use your new package. To do so, you need a custom prompt because LLMs were trained on data prior to your package’s existence. You can create a surprisingly useful tool just by preloading the prompt with your README and other documentation. This is how the chatlas assistant works.\nBuild language specific prompts for Python and/or R. Shiny assistant helps you build shiny apps (either in Python or R) by combining a prompt that gives general advice on building apps with a prompt for Python or R. The Python prompt is very detailed because there’s much less information about Shiny for Python in the existing LLM knowledgebases.\nHelp people find the answers to their questions. Even if you’ve written a bunch of documentation for something, you might find that you still get questions because folks can’t easily find exactly what they’re looking for. You can reduce the need to answer these questions by creating a chatbot with a prompt that contains your documentation. For example, if you’re a teacher, you could create a chatbot that includes your syllabus in the prompt. This eliminates a common class of question where the data necessary to answer the question is available, but hard to find.\n\nAnother direction is to give the chatbot additional context about your current environment. For example, aidea allows the user to interactively explore a dataset with the help of the LLM. It adds summary statistics about the dataset to the prompt so that the LLM knows something about your data. Along these lines, imagine writing a chatbot to help with data import that has a prompt which include all the files in the current directory along with their first few lines.\n\n\nStructured data extraction\nLLMs are often very good at extracting structured data from unstructured text. This can give you traction to analyse data that was previously unaccessible. For example:\n\nCustomer tickets and GitHub issues: you can use LLMs for quick and dirty sentiment analysis by extracting any specifically mentioned products and summarising the discussion as a few bullet points.\nGeocoding: LLMs do a surprisingly good job at geocoding, especially extracting addresses or finding the latitute/longitude of cities. There are specialised tools that do this better, but using an LLM makes it easy to get started.\nRecipes: I’ve extracted structured data from baking and cocktail recipes. Once you have the data in a structured form you can use your Python skills to better understand how recipes vary within a cookbook or to look for recipes that use the ingredients that you currently have in your kitchen. You could even use shiny assistant to help make those techniques available to anyone, not just Python users.\n\nStructured data extraction also work works well with images. It’s not the fastest or cheapest way to extract data but it makes it really easy to prototype ideas. For example, maybe you have a bunch of scanned documents that you want to index. You can convert PDFs to images (e.g. using something like pdf2image) then use structured data extraction to pull out key details.\nLearn more in the article on structured data extraction.\n\n\nProgramming\nLLMs can also be useful to solve general programming problems. For example:\n\nYou can use LLMs to explain code, or even ask them to generate a diagram.\nYou can ask an LLM to analyse your code for potential code smells or security issues. You can do this a function at a time, or explore including the entire source code for your package or script in the prompt.\nYou could automatically look up the documentation for an Python class/function, and include it in the prompt to make it easier to figure out how to use that class/function.\nI find it useful to have an LLM document a function for me, even knowing that it’s likely to be mostly incorrect. Having something to react to make it much easier for me to get started.\nIf you’re working with code or data from another programming language, you ask an LLM to convert it to Python code for you. Even if it’s not perfect, it’s still typically much faster than doing everything yourself.\nYou could use GitHub’s REST API to find unlabelled issues, extract the text, and ask the LLM to figure out what labels might be most appropriate. Or maybe an LLM might be able to help people create better reprexes, or simplify reprexes that are too complicated?\nWrite a detailed prompt that teaches the LLM about something it wouldn’t otherwise know about. For example, you might write a guide to updating code to use a new version of a package. If you have a programmable IDE, you could imagine being able to select code, transform it, and then replace the existing text. A real example of this is the R package pal, which includes prompts for updating source code to use the latest conventions in R for documentation, testing, error handling, and more." + "section": "Shiny", + "text": "Shiny\nUsing Shiny’s ui.Chat component, you can simply pass user input from the component into the chat.stream() method. This generate a response stream that can then be passed to .append_message_stream().\nfrom chatlas import ChatAnthropic\nfrom shiny.express import ui\n\nchat_ui = ui.Chat(\n id=\"ui_chat\",\n messages=[\"Hi! How can I help you today?\"],\n)\nchat_ui.ui()\n\nchat = ChatAnthropic()\n\n@chat_ui.on_user_submit\nasync def _():\n response = chat.stream(chat_ui.user_input())\n await chat_ui.append_message_stream(response)" }, { - "objectID": "get-started.html#miscellaneous", - "href": "get-started.html#miscellaneous", + "objectID": "web-apps.html#streamlit", + "href": "web-apps.html#streamlit", "title": "chatlas", - "section": "Miscellaneous", - "text": "Miscellaneous\nTo finish up here are a few other ideas that seem cool but didn’t seem to fit the above categories:\n\nAutomatically generate alt text for plots, using content_image_plot().\nAnalyse the text of your statistical report to look for flaws in your statistical reasoning (e.g. misinterpreting p-values or assuming causation where only correlation exists).\nUse your existing company style guide to generate a brand.yaml specification to automatically style your reports, apps, dashboards and plots to match your corporate style guide." + "section": "Streamlit", + "text": "Streamlit\nStreamlit is a popular Python library for building web apps. You can use the st.chat_input() and st.chat_message() methods to create a chat interface. Here’s an example of how you can use Chatlas with Streamlit:\nimport streamlit as st\nfrom chatlas import ChatOpenAI, Turn\n\nwith st.sidebar:\n openai_api_key = st.text_input(\n \"OpenAI API Key\", key=\"chatbot_api_key\", type=\"password\"\n )\n \"[Get an OpenAI API key](https://platform.openai.com/account/api-keys)\"\n \"[View the source code](https://github.com/streamlit/llm-examples/blob/main/Chatbot.py)\"\n\nst.title(\"💬 Chatbot\")\n\nif \"turns\" not in st.session_state:\n st.session_state[\"turns\"] = [\n Turn(role=\"assistant\", contents=\"How can I help you?\"),\n ]\n\nturns: list[Turn] = st.session_state.turns\n\nfor turn in turns:\n st.chat_message(turn.role).write(turn.text)\n\n\nif prompt := st.chat_input():\n if not openai_api_key:\n st.info(\"Please add your OpenAI API key to continue.\")\n st.stop()\n\n st.chat_message(\"user\").write(prompt)\n\n chat = ChatOpenAI(api_key=openai_api_key, turns=turns)\n response = chat.stream(prompt)\n\n with st.chat_message(\"assistant\"):\n st.write_stream(response)\n\n st.session_state[\"turns\"] = chat.get_turns()" }, { - "objectID": "reference/ChatGithub.html", - "href": "reference/ChatGithub.html", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html", + "href": "reference/ChatOllama.html", + "title": "ChatOllama", "section": "", - "text": "ChatGithub(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://models.inference.ai.azure.com/',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on the GitHub model marketplace.\nGitHub (via Azure) hosts a wide variety of open source models, some of which are fined tuned for specific tasks.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://github.com/marketplace/models to get an API key. You may need to apply for and be accepted into a beta access program.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGithub requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGithub\n\nchat = ChatGithub(api_key=os.getenv(\"GITHUB_PAT\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GITHUB_PAT environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Github’s API.\n'https://models.inference.ai.azure.com/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for the GitHub model marketplace.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGithub(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGITHUB_PAT=...\nfrom chatlas import ChatGithub\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGithub()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GITHUB_PAT=...", + "text": "ChatOllama(\n model=None,\n *,\n system_prompt=None,\n turns=None,\n base_url='http://localhost:11434',\n seed=None,\n kwargs=None,\n)\nChat with a local Ollama model.\nOllama makes it easy to run a wide-variety of open-source models locally, making it a great choice for privacy and security.\n\n\n\n\n\n\n\n\nOllama runtime\n\n\n\nChatOllama requires the ollama executable to be installed and running on your machine.\n\n\n\n\n\n\n\n\nPull model(s)\n\n\n\nOnce ollama is running locally, download a model from the command line (e.g. ollama pull llama3.2).\n\n\n\n\n\nfrom chatlas import ChatOllama\n\nchat = ChatOllama(model=\"llama3.2\")\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat. If None, a list of locally installed models will be printed.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses ollama’s API.\n'http://localhost:11434'\n\n\nseed\nOptional[int]\nOptional integer seed that helps to make output more reproducible.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for ollama.\n\n\n\nChatOllama currently doesn’t work with streaming tools, and tool calling more generally doesn’t seem to work very well with currently available models.", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] }, { - "objectID": "reference/ChatGithub.html#prerequisites", - "href": "reference/ChatGithub.html#prerequisites", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html#prerequisites", + "href": "reference/ChatOllama.html#prerequisites", + "title": "ChatOllama", "section": "", - "text": "API key\n\n\n\nSign up at https://github.com/marketplace/models to get an API key. You may need to apply for and be accepted into a beta access program.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGithub requires the openai package (e.g., pip install openai).", + "text": "Ollama runtime\n\n\n\nChatOllama requires the ollama executable to be installed and running on your machine.\n\n\n\n\n\n\n\n\nPull model(s)\n\n\n\nOnce ollama is running locally, download a model from the command line (e.g. ollama pull llama3.2).", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] }, { - "objectID": "reference/ChatGithub.html#examples", - "href": "reference/ChatGithub.html#examples", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html#examples", + "href": "reference/ChatOllama.html#examples", + "title": "ChatOllama", "section": "", - "text": "import os\nfrom chatlas import ChatGithub\n\nchat = ChatGithub(api_key=os.getenv(\"GITHUB_PAT\"))\nchat.chat(\"What is the capital of France?\")", + "text": "from chatlas import ChatOllama\n\nchat = ChatOllama(model=\"llama3.2\")\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] }, { - "objectID": "reference/ChatGithub.html#parameters", - "href": "reference/ChatGithub.html#parameters", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html#parameters", + "href": "reference/ChatOllama.html#parameters", + "title": "ChatOllama", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GITHUB_PAT environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Github’s API.\n'https://models.inference.ai.azure.com/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat. If None, a list of locally installed models will be printed.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses ollama’s API.\n'http://localhost:11434'\n\n\nseed\nOptional[int]\nOptional integer seed that helps to make output more reproducible.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] }, { - "objectID": "reference/ChatGithub.html#returns", - "href": "reference/ChatGithub.html#returns", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html#note", + "href": "reference/ChatOllama.html#note", + "title": "ChatOllama", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", + "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for ollama.", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] }, { - "objectID": "reference/ChatGithub.html#note", - "href": "reference/ChatGithub.html#note", - "title": "ChatGithub", + "objectID": "reference/ChatOllama.html#limitations", + "href": "reference/ChatOllama.html#limitations", + "title": "ChatOllama", "section": "", - "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for the GitHub model marketplace.", + "text": "ChatOllama currently doesn’t work with streaming tools, and tool calling more generally doesn’t seem to work very well with currently available models.", "crumbs": [ "Reference", "Chat model providers", - "ChatGithub" + "ChatOllama" ] - }, - { - "objectID": "reference/ChatGithub.html#note-1", - "href": "reference/ChatGithub.html#note-1", - "title": "ChatGithub", + }, + { + "objectID": "reference/Chat.html", + "href": "reference/Chat.html", + "title": "Chat", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatGithub(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGITHUB_PAT=...\nfrom chatlas import ChatGithub\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGithub()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GITHUB_PAT=...", + "text": "Chat(self, provider, turns=None)\nA chat object that can be used to interact with a language model.\nA Chat is an sequence of sequence of user and assistant Turns sent to a specific Provider. A Chat takes care of managing the state associated with the chat; i.e. it records the messages that you send to the server, and the messages that you receive back. If you register a tool (i.e. an function that the assistant can call on your behalf), it also takes care of the tool loop.\nYou should generally not create this object yourself, but instead call ChatOpenAI or friends instead.\n\n\n\n\n\nName\nDescription\n\n\n\n\nsystem_prompt\nA property to get (or set) the system prompt for the chat.\n\n\n\n\n\n\n\n\n\nName\nDescription\n\n\n\n\napp\nEnter a web-based chat app to interact with the LLM.\n\n\nchat\nGenerate a response from the chat.\n\n\nchat_async\nGenerate a response from the chat asynchronously.\n\n\nconsole\nEnter a chat console to interact with the LLM.\n\n\nexport\nExport the chat history to a file.\n\n\nextract_data\nExtract structured data from the given input.\n\n\nextract_data_async\nExtract structured data from the given input asynchronously.\n\n\nget_last_turn\nGet the last turn in the chat with a specific role.\n\n\nget_turns\nGet all the turns (i.e., message contents) in the chat.\n\n\nregister_tool\nRegister a tool (function) with the chat.\n\n\nset_echo_options\nSet echo styling options for the chat.\n\n\nset_turns\nSet the turns of the chat.\n\n\nstream\nGenerate a response from the chat in a streaming fashion.\n\n\nstream_async\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\ntokens\nGet the tokens for each turn in the chat.\n\n\n\n\n\nChat.app(stream=True, port=0, launch_browser=True, bg_thread=None, kwargs=None)\nEnter a web-based chat app to interact with the LLM.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nport\nint\nThe port to run the app on (the default is 0, which will choose a random port).\n0\n\n\nlaunch_browser\nbool\nWhether to launch a browser window.\nTrue\n\n\nbg_thread\nOptional[bool]\nWhether to run the app in a background thread. If None, the app will run in a background thread if the current environment is a notebook.\nNone\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\nChat.chat(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.chat_async(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls, images, etc), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.console(echo='text', stream=True, kwargs=None)\nEnter a chat console to interact with the LLM.\nTo quit, input ‘exit’ or press Ctrl+C.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\nChat.export(\n filename,\n *,\n turns=None,\n title=None,\n include='text',\n include_system_prompt=True,\n overwrite=False,\n)\nExport the chat history to a file.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfilename\nstr | Path\nThe filename to export the chat to. Currently this must be a .md or .html file.\nrequired\n\n\nturns\nOptional[Sequence[Turn]]\nThe .get_turns() to export. If not provided, the chat’s current turns will be used.\nNone\n\n\ntitle\nOptional[str]\nA title to place at the top of the exported file.\nNone\n\n\noverwrite\nbool\nWhether to overwrite the file if it already exists.\nFalse\n\n\ninclude\nLiteral['text', 'all']\nWhether to include text content, all content (i.e., tool calls), or no content.\n'text'\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in a \nTrue\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nPath\nThe path to the exported file.\n\n\n\n\n\n\n\nChat.extract_data(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.extract_data_async(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks). Defaults to True if echo is not “none”.\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.get_last_turn(role='assistant')\nGet the last turn in the chat with a specific role.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['assistant', 'user', 'system']\nThe role of the turn to return.\n'assistant'\n\n\n\n\n\n\n\nChat.get_turns(include_system_prompt=False)\nGet all the turns (i.e., message contents) in the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in the turns.\nFalse\n\n\n\n\n\n\n\nChat.register_tool(func, *, model=None)\nRegister a tool (function) with the chat.\nThe function will always be invoked in the current Python process.\n\n\nIf your tool has straightforward input parameters, you can just register the function directly (type hints and a docstring explaning both what the function does and what the parameters are for is strongly recommended):\nfrom chatlas import ChatOpenAI, Tool\n\n\ndef add(a: int, b: int) -> int:\n '''\n Add two numbers together.\n\n#### Parameters {.doc-section .doc-section-----parameters}\n\n a : int\n The first number to add.\n b : int\n The second number to add.\n '''\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add)\nchat.chat(\"What is 2 + 2?\")\nIf your tool has more complex input parameters, you can provide a Pydantic model that corresponds to the input parameters for the function, This way, you can have fields that hold other model(s) (for more complex input parameters), and also more directly document the input parameters:\nfrom chatlas import ChatOpenAI, Tool\nfrom pydantic import BaseModel, Field\n\n\nclass AddParams(BaseModel):\n '''Add two numbers together.'''\n\n a: int = Field(description=\"The first number to add.\")\n\n b: int = Field(description=\"The second number to add.\")\n\n\ndef add(a: int, b: int) -> int:\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add, model=AddParams)\nchat.chat(\"What is 2 + 2?\")\n\n\n\n\n\nfunc The function to be invoked when the tool is called. model A Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\n\n\nChat.set_echo_options(rich_markdown=None, rich_console=None, css_styles=None)\nSet echo styling options for the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrich_markdown\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.markdown.Markdown(). This is only relevant when outputting to the console.\nNone\n\n\nrich_console\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.console.Console(). This is only relevant when outputting to the console.\nNone\n\n\ncss_styles\nOptional[dict[str, str]]\nA dictionary of CSS styles to apply to IPython.display.Markdown(). This is only relevant when outputing to the browser.\nNone\n\n\n\n\n\n\n\nChat.set_turns(turns)\nSet the turns of the chat.\nThis method is primarily useful for clearing or setting the turns of the chat (i.e., limiting the context window).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nturns\nSequence[Turn]\nThe turns to set. Turns with the role “system” are not allowed.\nrequired\n\n\n\n\n\n\n\nChat.stream(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.stream_async(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.tokens()\nGet the tokens for each turn in the chat.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[tuple[int, int] | None]\nA list of tuples, where each tuple contains the start and end token indices for a turn.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGithub" + "The chat object", + "Chat" ] }, { - "objectID": "reference/ChatAzureOpenAI.html", - "href": "reference/ChatAzureOpenAI.html", - "title": "ChatAzureOpenAI", + "objectID": "reference/Chat.html#attributes", + "href": "reference/Chat.html#attributes", + "title": "Chat", "section": "", - "text": "ChatAzureOpenAI(\n endpoint,\n deployment_id,\n api_version,\n api_key=None,\n system_prompt=None,\n turns=None,\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on Azure OpenAI.\nThe Azure OpenAI server hosts a number of open source models as well as proprietary models from OpenAI.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAzureOpenAI requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatAzureOpenAI\n\nchat = ChatAzureOpenAI(\n endpoint=os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n deployment_id=\"REPLACE_WITH_YOUR_DEPLOYMENT_ID\",\n api_version=\"YYYY-MM-DD\",\n api_key=os.getenv(\"AZURE_OPENAI_API_KEY\"),\n)\n\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nendpoint\nstr\nAzure OpenAI endpoint url with protocol and hostname, i.e. https://{your-resource-name}.openai.azure.com. Defaults to using the value of the AZURE_OPENAI_ENDPOINT envinronment variable.\nrequired\n\n\ndeployment_id\nstr\nDeployment id for the model you want to use.\nrequired\n\n\napi_version\nstr\nThe API version to use.\nrequired\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the AZURE_OPENAI_API_KEY environment variable.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatAzureClientArgs']\nAdditional arguments to pass to the openai.AzureOpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "Name\nDescription\n\n\n\n\nsystem_prompt\nA property to get (or set) the system prompt for the chat.", "crumbs": [ "Reference", - "Chat model providers", - "ChatAzureOpenAI" + "The chat object", + "Chat" ] }, { - "objectID": "reference/ChatAzureOpenAI.html#prerequisites", - "href": "reference/ChatAzureOpenAI.html#prerequisites", - "title": "ChatAzureOpenAI", + "objectID": "reference/Chat.html#methods", + "href": "reference/Chat.html#methods", + "title": "Chat", "section": "", - "text": "Python requirements\n\n\n\nChatAzureOpenAI requires the openai package (e.g., pip install openai).", + "text": "Name\nDescription\n\n\n\n\napp\nEnter a web-based chat app to interact with the LLM.\n\n\nchat\nGenerate a response from the chat.\n\n\nchat_async\nGenerate a response from the chat asynchronously.\n\n\nconsole\nEnter a chat console to interact with the LLM.\n\n\nexport\nExport the chat history to a file.\n\n\nextract_data\nExtract structured data from the given input.\n\n\nextract_data_async\nExtract structured data from the given input asynchronously.\n\n\nget_last_turn\nGet the last turn in the chat with a specific role.\n\n\nget_turns\nGet all the turns (i.e., message contents) in the chat.\n\n\nregister_tool\nRegister a tool (function) with the chat.\n\n\nset_echo_options\nSet echo styling options for the chat.\n\n\nset_turns\nSet the turns of the chat.\n\n\nstream\nGenerate a response from the chat in a streaming fashion.\n\n\nstream_async\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\ntokens\nGet the tokens for each turn in the chat.\n\n\n\n\n\nChat.app(stream=True, port=0, launch_browser=True, bg_thread=None, kwargs=None)\nEnter a web-based chat app to interact with the LLM.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nport\nint\nThe port to run the app on (the default is 0, which will choose a random port).\n0\n\n\nlaunch_browser\nbool\nWhether to launch a browser window.\nTrue\n\n\nbg_thread\nOptional[bool]\nWhether to run the app in a background thread. If None, the app will run in a background thread if the current environment is a notebook.\nNone\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\nChat.chat(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.chat_async(*args, echo='text', stream=True, kwargs=None)\nGenerate a response from the chat asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls, images, etc), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nA (consumed) response from the chat. Apply str() to this object to get the text content of the response.\n\n\n\n\n\n\n\nChat.console(echo='text', stream=True, kwargs=None)\nEnter a chat console to interact with the LLM.\nTo quit, input ‘exit’ or press Ctrl+C.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'text'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nTrue\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\nChat.export(\n filename,\n *,\n turns=None,\n title=None,\n include='text',\n include_system_prompt=True,\n overwrite=False,\n)\nExport the chat history to a file.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfilename\nstr | Path\nThe filename to export the chat to. Currently this must be a .md or .html file.\nrequired\n\n\nturns\nOptional[Sequence[Turn]]\nThe .get_turns() to export. If not provided, the chat’s current turns will be used.\nNone\n\n\ntitle\nOptional[str]\nA title to place at the top of the exported file.\nNone\n\n\noverwrite\nbool\nWhether to overwrite the file if it already exists.\nFalse\n\n\ninclude\nLiteral['text', 'all']\nWhether to include text content, all content (i.e., tool calls), or no content.\n'text'\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in a \nTrue\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nPath\nThe path to the exported file.\n\n\n\n\n\n\n\nChat.extract_data(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks).\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.extract_data_async(*args, data_model, echo='none', stream=False)\nExtract structured data from the given input asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe input to extract data from.\n()\n\n\ndata_model\ntype[BaseModel]\nA Pydantic model describing the structure of the data to extract.\nrequired\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content\n'none'\n\n\nstream\nbool\nWhether to stream the response (i.e., have the response appear in chunks). Defaults to True if echo is not “none”.\nFalse\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict[str, Any]\nThe extracted data.\n\n\n\n\n\n\n\nChat.get_last_turn(role='assistant')\nGet the last turn in the chat with a specific role.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['assistant', 'user', 'system']\nThe role of the turn to return.\n'assistant'\n\n\n\n\n\n\n\nChat.get_turns(include_system_prompt=False)\nGet all the turns (i.e., message contents) in the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ninclude_system_prompt\nbool\nWhether to include the system prompt in the turns.\nFalse\n\n\n\n\n\n\n\nChat.register_tool(func, *, model=None)\nRegister a tool (function) with the chat.\nThe function will always be invoked in the current Python process.\n\n\nIf your tool has straightforward input parameters, you can just register the function directly (type hints and a docstring explaning both what the function does and what the parameters are for is strongly recommended):\nfrom chatlas import ChatOpenAI, Tool\n\n\ndef add(a: int, b: int) -> int:\n '''\n Add two numbers together.\n\n#### Parameters {.doc-section .doc-section-----parameters}\n\n a : int\n The first number to add.\n b : int\n The second number to add.\n '''\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add)\nchat.chat(\"What is 2 + 2?\")\nIf your tool has more complex input parameters, you can provide a Pydantic model that corresponds to the input parameters for the function, This way, you can have fields that hold other model(s) (for more complex input parameters), and also more directly document the input parameters:\nfrom chatlas import ChatOpenAI, Tool\nfrom pydantic import BaseModel, Field\n\n\nclass AddParams(BaseModel):\n '''Add two numbers together.'''\n\n a: int = Field(description=\"The first number to add.\")\n\n b: int = Field(description=\"The second number to add.\")\n\n\ndef add(a: int, b: int) -> int:\n return a + b\n\n\nchat = ChatOpenAI()\nchat.register_tool(add, model=AddParams)\nchat.chat(\"What is 2 + 2?\")", "crumbs": [ "Reference", - "Chat model providers", - "ChatAzureOpenAI" + "The chat object", + "Chat" ] }, { - "objectID": "reference/ChatAzureOpenAI.html#examples", - "href": "reference/ChatAzureOpenAI.html#examples", - "title": "ChatAzureOpenAI", + "objectID": "reference/Chat.html#parameters-9", + "href": "reference/Chat.html#parameters-9", + "title": "Chat", "section": "", - "text": "import os\nfrom chatlas import ChatAzureOpenAI\n\nchat = ChatAzureOpenAI(\n endpoint=os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n deployment_id=\"REPLACE_WITH_YOUR_DEPLOYMENT_ID\",\n api_version=\"YYYY-MM-DD\",\n api_key=os.getenv(\"AZURE_OPENAI_API_KEY\"),\n)\n\nchat.chat(\"What is the capital of France?\")", + "text": "func The function to be invoked when the tool is called. model A Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\n\n\nChat.set_echo_options(rich_markdown=None, rich_console=None, css_styles=None)\nSet echo styling options for the chat.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrich_markdown\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.markdown.Markdown(). This is only relevant when outputting to the console.\nNone\n\n\nrich_console\nOptional[dict[str, Any]]\nA dictionary of options to pass to rich.console.Console(). This is only relevant when outputting to the console.\nNone\n\n\ncss_styles\nOptional[dict[str, str]]\nA dictionary of CSS styles to apply to IPython.display.Markdown(). This is only relevant when outputing to the browser.\nNone\n\n\n\n\n\n\n\nChat.set_turns(turns)\nSet the turns of the chat.\nThis method is primarily useful for clearing or setting the turns of the chat (i.e., limiting the context window).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nturns\nSequence[Turn]\nThe turns to set. Turns with the role “system” are not allowed.\nrequired\n\n\n\n\n\n\n\nChat.stream(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponse\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.stream_async(*args, echo='none', kwargs=None)\nGenerate a response from the chat in a streaming fashion asynchronously.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nargs\nContent | str\nThe user input(s) to generate a response from.\n()\n\n\necho\nLiteral['text', 'all', 'none']\nWhether to echo text content, all content (i.e., tool calls), or no content.\n'none'\n\n\nkwargs\nOptional[SubmitInputArgsT]\nAdditional keyword arguments to pass to the method used for requesting the response.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChatResponseAsync\nAn (unconsumed) response from the chat. Iterate over this object to consume the response.\n\n\n\n\n\n\n\nChat.tokens()\nGet the tokens for each turn in the chat.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[tuple[int, int] | None]\nA list of tuples, where each tuple contains the start and end token indices for a turn.", "crumbs": [ "Reference", - "Chat model providers", - "ChatAzureOpenAI" + "The chat object", + "Chat" ] }, { - "objectID": "reference/ChatAzureOpenAI.html#parameters", - "href": "reference/ChatAzureOpenAI.html#parameters", - "title": "ChatAzureOpenAI", + "objectID": "reference/interpolate_file.html", + "href": "reference/interpolate_file.html", + "title": "interpolate_file", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nendpoint\nstr\nAzure OpenAI endpoint url with protocol and hostname, i.e. https://{your-resource-name}.openai.azure.com. Defaults to using the value of the AZURE_OPENAI_ENDPOINT envinronment variable.\nrequired\n\n\ndeployment_id\nstr\nDeployment id for the model you want to use.\nrequired\n\n\napi_version\nstr\nThe API version to use.\nrequired\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the AZURE_OPENAI_API_KEY environment variable.\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatAzureClientArgs']\nAdditional arguments to pass to the openai.AzureOpenAI() client constructor.\nNone", + "text": "interpolate_file(\n path,\n *,\n variables=None,\n variable_start='{{',\n variable_end='}}',\n)\nInterpolate variables into a prompt from a file\nThis is a light-weight wrapper around the Jinja2 templating engine, making it easier to interpolate dynamic data into a static prompt. Compared to f-strings, which expects you to wrap dynamic values in { }, this function expects { } instead, making it easier to include Python code and JSON in your prompt.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nUnion[str, Path]\nThe path to the file containing the prompt to interpolate.\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.\n\n\n\n\n\n\ninterpolate Interpolating data into a system prompt", "crumbs": [ "Reference", - "Chat model providers", - "ChatAzureOpenAI" + "Prompt interpolation", + "interpolate_file" ] }, { - "objectID": "reference/ChatAzureOpenAI.html#returns", - "href": "reference/ChatAzureOpenAI.html#returns", - "title": "ChatAzureOpenAI", + "objectID": "reference/interpolate_file.html#parameters", + "href": "reference/interpolate_file.html#parameters", + "title": "interpolate_file", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nUnion[str, Path]\nThe path to the file containing the prompt to interpolate.\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'", "crumbs": [ "Reference", - "Chat model providers", - "ChatAzureOpenAI" + "Prompt interpolation", + "interpolate_file" ] }, { - "objectID": "reference/Turn.html", - "href": "reference/Turn.html", - "title": "Turn", + "objectID": "reference/interpolate_file.html#returns", + "href": "reference/interpolate_file.html#returns", + "title": "interpolate_file", "section": "", - "text": "Turn(self, role, contents, *, tokens=None, finish_reason=None, completion=None)\nA user or assistant turn\nEvery conversation with a chatbot consists of pairs of user and assistant turns, corresponding to an HTTP request and response. These turns are represented by the Turn object, which contains a list of Contents representing the individual messages within the turn. These might be text, images, tool requests (assistant only), or tool responses (user only).\nNote that a call to .chat() and related functions may result in multiple user-assistant turn cycles. For example, if you have registered tools, chatlas will automatically handle the tool calling loop, which may result in any number of additional cycles.\n\n\nfrom chatlas import Turn, ChatOpenAI, ChatAnthropic\n\nchat = ChatOpenAI()\nstr(chat.chat(\"What is the capital of France?\"))\nturns = chat.get_turns()\nassert len(turns) == 2\nassert isinstance(turns[0], Turn)\nassert turns[0].role == \"user\"\nassert turns[1].role == \"assistant\"\n\n# Load context into a new chat instance\nchat2 = ChatAnthropic(turns=turns)\nturns2 = chat2.get_turns()\nassert turns == turns2\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['user', 'assistant', 'system']\nEither “user”, “assistant”, or “system”.\nrequired\n\n\ncontents\nstr | Sequence[Content | str]\nA list of Content objects.\nrequired\n\n\ntokens\nOptional[tuple[int, int]]\nA numeric vector of length 2 representing the number of input and output tokens (respectively) used in this turn. Currently only recorded for assistant turns.\nNone\n\n\nfinish_reason\nOptional[str]\nA string indicating the reason why the conversation ended. This is only relevant for assistant turns.\nNone\n\n\ncompletion\nOptional[CompletionT]\nThe completion object returned by the provider. This is useful if there’s information returned by the provider that chatlas doesn’t otherwise expose. This is only relevant for assistant turns.\nNone", + "text": "Name\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.", "crumbs": [ "Reference", - "Turns", - "Turn" + "Prompt interpolation", + "interpolate_file" ] }, { - "objectID": "reference/Turn.html#examples", - "href": "reference/Turn.html#examples", - "title": "Turn", + "objectID": "reference/interpolate_file.html#see-also", + "href": "reference/interpolate_file.html#see-also", + "title": "interpolate_file", "section": "", - "text": "from chatlas import Turn, ChatOpenAI, ChatAnthropic\n\nchat = ChatOpenAI()\nstr(chat.chat(\"What is the capital of France?\"))\nturns = chat.get_turns()\nassert len(turns) == 2\nassert isinstance(turns[0], Turn)\nassert turns[0].role == \"user\"\nassert turns[1].role == \"assistant\"\n\n# Load context into a new chat instance\nchat2 = ChatAnthropic(turns=turns)\nturns2 = chat2.get_turns()\nassert turns == turns2", + "text": "interpolate Interpolating data into a system prompt", "crumbs": [ "Reference", - "Turns", - "Turn" + "Prompt interpolation", + "interpolate_file" ] }, { - "objectID": "reference/Turn.html#parameters", - "href": "reference/Turn.html#parameters", - "title": "Turn", + "objectID": "reference/ChatAnthropic.html", + "href": "reference/ChatAnthropic.html", + "title": "ChatAnthropic", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nrole\nLiteral['user', 'assistant', 'system']\nEither “user”, “assistant”, or “system”.\nrequired\n\n\ncontents\nstr | Sequence[Content | str]\nA list of Content objects.\nrequired\n\n\ntokens\nOptional[tuple[int, int]]\nA numeric vector of length 2 representing the number of input and output tokens (respectively) used in this turn. Currently only recorded for assistant turns.\nNone\n\n\nfinish_reason\nOptional[str]\nA string indicating the reason why the conversation ended. This is only relevant for assistant turns.\nNone\n\n\ncompletion\nOptional[CompletionT]\nThe completion object returned by the provider. This is useful if there’s information returned by the provider that chatlas doesn’t otherwise expose. This is only relevant for assistant turns.\nNone", + "text": "ChatAnthropic(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n max_tokens=4096,\n kwargs=None,\n)\nChat with an Anthropic Claude model.\nAnthropic provides a number of chat based models under the Claude moniker.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nNote that a Claude Prop membership does not give you the ability to call models via the API. You will need to go to the developer console to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAnthropic requires the anthropic package (e.g., pip install anthropic).\n\n\n\n\n\nimport os\nfrom chatlas import ChatAnthropic\n\nchat = ChatAnthropic(api_key=os.getenv(\"ANTHROPIC_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ModelParam]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the ANTHROPIC_API_KEY environment variable.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the anthropic.Anthropic() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.\n\n\n\n\n\n\nPasting an API key into a chat constructor (e.g., ChatAnthropic(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nANTHROPIC_API_KEY=...\nfrom chatlas import ChatAnthropic\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatAnthropic()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport ANTHROPIC_API_KEY=...", "crumbs": [ "Reference", - "Turns", - "Turn" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/content_image_plot.html", - "href": "reference/content_image_plot.html", - "title": "content_image_plot", + "objectID": "reference/ChatAnthropic.html#prerequisites", + "href": "reference/ChatAnthropic.html#prerequisites", + "title": "ChatAnthropic", "section": "", - "text": "content_image_plot(width=768, height=768, dpi=72)\nEncode the current matplotlib plot as an image for chat input.\nThis function captures the current matplotlib plot, resizes it to the specified dimensions, and prepares it for chat input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)", + "text": "API key\n\n\n\nNote that a Claude Prop membership does not give you the ability to call models via the API. You will need to go to the developer console to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatAnthropic requires the anthropic package (e.g., pip install anthropic).", "crumbs": [ "Reference", - "Image input", - "content_image_plot" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/content_image_plot.html#parameters", - "href": "reference/content_image_plot.html#parameters", - "title": "content_image_plot", + "objectID": "reference/ChatAnthropic.html#examples", + "href": "reference/ChatAnthropic.html#examples", + "title": "ChatAnthropic", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72", + "text": "import os\nfrom chatlas import ChatAnthropic\n\nchat = ChatAnthropic(api_key=os.getenv(\"ANTHROPIC_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", - "Image input", - "content_image_plot" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/content_image_plot.html#returns", - "href": "reference/content_image_plot.html#returns", - "title": "content_image_plot", + "objectID": "reference/ChatAnthropic.html#parameters", + "href": "reference/ChatAnthropic.html#parameters", + "title": "ChatAnthropic", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ModelParam]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the ANTHROPIC_API_KEY environment variable.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the anthropic.Anthropic() client constructor.\nNone", "crumbs": [ "Reference", - "Image input", - "content_image_plot" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/content_image_plot.html#raises", - "href": "reference/content_image_plot.html#raises", - "title": "content_image_plot", + "objectID": "reference/ChatAnthropic.html#returns", + "href": "reference/ChatAnthropic.html#returns", + "title": "ChatAnthropic", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", - "Image input", - "content_image_plot" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/content_image_plot.html#examples", - "href": "reference/content_image_plot.html#examples", - "title": "content_image_plot", + "objectID": "reference/ChatAnthropic.html#note", + "href": "reference/ChatAnthropic.html#note", + "title": "ChatAnthropic", "section": "", - "text": "from chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)", + "text": "Pasting an API key into a chat constructor (e.g., ChatAnthropic(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nANTHROPIC_API_KEY=...\nfrom chatlas import ChatAnthropic\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatAnthropic()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport ANTHROPIC_API_KEY=...", "crumbs": [ "Reference", - "Image input", - "content_image_plot" + "Chat model providers", + "ChatAnthropic" ] }, { - "objectID": "reference/types.ContentToolRequest.html", - "href": "reference/types.ContentToolRequest.html", - "title": "types.ContentToolRequest", + "objectID": "reference/content_image_file.html", + "href": "reference/content_image_file.html", + "title": "content_image_file", "section": "", - "text": "types.ContentToolRequest(self, id, name, arguments)\nA request to call a tool/function\nThis content type isn’t meant to be used directly. Instead, it’s automatically generated by Chat when a tool/function is requested by the model assistant.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nA unique identifier for this request.\nrequired\n\n\nname\nstr\nThe name of the tool/function to call.\nrequired\n\n\narguments\nobject\nThe arguments to pass to the tool/function.\nrequired", + "text": "content_image_file(path, content_type='auto', resize=MISSING)\nEncode image content from a file for chat input.\nThis function is used to prepare image files for input to the chatbot. It can handle various image formats and provides options for resizing.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[Literal['low', 'high', 'none'], str, MISSING_TYPE]\nResizing option for the image. Can be: - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - \"none\": No resizing - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\nMISSING\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid.", "crumbs": [ "Reference", - "User-facing types", - "types.ContentToolRequest" + "Image input", + "content_image_file" ] }, { - "objectID": "reference/types.ContentToolRequest.html#parameters", - "href": "reference/types.ContentToolRequest.html#parameters", - "title": "types.ContentToolRequest", + "objectID": "reference/content_image_file.html#parameters", + "href": "reference/content_image_file.html#parameters", + "title": "content_image_file", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nA unique identifier for this request.\nrequired\n\n\nname\nstr\nThe name of the tool/function to call.\nrequired\n\n\narguments\nobject\nThe arguments to pass to the tool/function.\nrequired", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[Literal['low', 'high', 'none'], str, MISSING_TYPE]\nResizing option for the image. Can be: - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - \"none\": No resizing - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\nMISSING", "crumbs": [ "Reference", - "User-facing types", - "types.ContentToolRequest" + "Image input", + "content_image_file" ] }, { - "objectID": "reference/types.ContentText.html", - "href": "reference/types.ContentText.html", - "title": "types.ContentText", + "objectID": "reference/content_image_file.html#returns", + "href": "reference/content_image_file.html#returns", + "title": "content_image_file", "section": "", - "text": "types.ContentText\ntypes.ContentText(self, text)\nText content for a Turn", + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", "crumbs": [ "Reference", - "User-facing types", - "types.ContentText" + "Image input", + "content_image_file" ] }, { - "objectID": "reference/types.MISSING.html", - "href": "reference/types.MISSING.html", - "title": "types.MISSING", + "objectID": "reference/content_image_file.html#examples", + "href": "reference/content_image_file.html#examples", + "title": "content_image_file", "section": "", - "text": "types.MISSING\ntypes.MISSING", + "text": "from chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)", "crumbs": [ "Reference", - "User-facing types", - "types.MISSING" + "Image input", + "content_image_file" ] }, { - "objectID": "reference/types.ContentImageRemote.html", - "href": "reference/types.ContentImageRemote.html", - "title": "types.ContentImageRemote", + "objectID": "reference/content_image_file.html#raises", + "href": "reference/content_image_file.html#raises", + "title": "content_image_file", "section": "", - "text": "types.ContentImageRemote(self, url, detail='auto')\nImage content from a URL.\nThis is the return type for content_image_url. It’s not meant to be used directly.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nA detail setting for the image. Can be \"auto\", \"low\", or \"high\".\n'auto'", + "text": "Name\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid.", "crumbs": [ "Reference", - "User-facing types", - "types.ContentImageRemote" + "Image input", + "content_image_file" ] }, { - "objectID": "reference/types.ContentImageRemote.html#parameters", - "href": "reference/types.ContentImageRemote.html#parameters", - "title": "types.ContentImageRemote", + "objectID": "reference/ChatOpenAI.html", + "href": "reference/ChatOpenAI.html", + "title": "ChatOpenAI", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nA detail setting for the image. Can be \"auto\", \"low\", or \"high\".\n'auto'", + "text": "ChatOpenAI(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.openai.com/v1',\n seed=MISSING,\n kwargs=None,\n)\nChat with an OpenAI model.\nOpenAI provides a number of chat based models under the ChatGPT moniker.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nNote that a ChatGPT Plus membership does not give you the ability to call models via the API. You will need to go to the developer platform to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatOpenAI requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ChatModel | str]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the OPENAI_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses OpenAI.\n'https://api.openai.com/v1'\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nPasting an API key into a chat constructor (e.g., ChatOpenAI(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nOPENAI_API_KEY=...\nfrom chatlas import ChatOpenAI\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatOpenAI()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport OPENAI_API_KEY=...", "crumbs": [ "Reference", - "User-facing types", - "types.ContentImageRemote" + "Chat model providers", + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html", - "href": "reference/ChatGroq.html", - "title": "ChatGroq", + "objectID": "reference/ChatOpenAI.html#prerequisites", + "href": "reference/ChatOpenAI.html#prerequisites", + "title": "ChatOpenAI", "section": "", - "text": "ChatGroq(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.groq.com/openai/v1',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on Groq.\nGroq provides a platform for highly efficient AI inference.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://groq.com to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGroq requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGroq\n\nchat = ChatGroq(api_key=os.getenv(\"GROQ_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GROQ_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Groq’s API.\n'https://api.groq.com/openai/v1'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for groq.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGroq(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGROQ_API_KEY=...\nfrom chatlas import ChatGroq\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGroq()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GROQ_API_KEY=...", + "text": "API key\n\n\n\nNote that a ChatGPT Plus membership does not give you the ability to call models via the API. You will need to go to the developer platform to sign up (and pay for) a developer account that will give you an API key that you can use with this package.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatOpenAI requires the openai package (e.g., pip install openai).", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html#prerequisites", - "href": "reference/ChatGroq.html#prerequisites", - "title": "ChatGroq", + "objectID": "reference/ChatOpenAI.html#examples", + "href": "reference/ChatOpenAI.html#examples", + "title": "ChatOpenAI", "section": "", - "text": "API key\n\n\n\nSign up at https://groq.com to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGroq requires the openai package (e.g., pip install openai).", + "text": "import os\nfrom chatlas import ChatOpenAI\n\nchat = ChatOpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html#examples", - "href": "reference/ChatGroq.html#examples", - "title": "ChatGroq", + "objectID": "reference/ChatOpenAI.html#parameters", + "href": "reference/ChatOpenAI.html#parameters", + "title": "ChatOpenAI", "section": "", - "text": "import os\nfrom chatlas import ChatGroq\n\nchat = ChatGroq(api_key=os.getenv(\"GROQ_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\n'Optional[ChatModel | str]'\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the OPENAI_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses OpenAI.\n'https://api.openai.com/v1'\n\n\nseed\nint | None | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html#parameters", - "href": "reference/ChatGroq.html#parameters", - "title": "ChatGroq", + "objectID": "reference/ChatOpenAI.html#returns", + "href": "reference/ChatOpenAI.html#returns", + "title": "ChatOpenAI", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GROQ_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Groq’s API.\n'https://api.groq.com/openai/v1'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html#returns", - "href": "reference/ChatGroq.html#returns", - "title": "ChatGroq", + "objectID": "reference/ChatOpenAI.html#note", + "href": "reference/ChatOpenAI.html#note", + "title": "ChatOpenAI", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", + "text": "Pasting an API key into a chat constructor (e.g., ChatOpenAI(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nOPENAI_API_KEY=...\nfrom chatlas import ChatOpenAI\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatOpenAI()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport OPENAI_API_KEY=...", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatOpenAI" ] }, { - "objectID": "reference/ChatGroq.html#note", - "href": "reference/ChatGroq.html#note", - "title": "ChatGroq", + "objectID": "reference/ChatBedrockAnthropic.html", + "href": "reference/ChatBedrockAnthropic.html", + "title": "ChatBedrockAnthropic", "section": "", - "text": "This function is a lightweight wrapper around ChatOpenAI with the defaults tweaked for groq.", + "text": "ChatBedrockAnthropic(\n model=None,\n max_tokens=4096,\n aws_secret_key=None,\n aws_access_key=None,\n aws_region=None,\n aws_profile=None,\n aws_session_token=None,\n base_url=None,\n system_prompt=None,\n turns=None,\n kwargs=None,\n)\nChat with an AWS bedrock model.\nAWS Bedrock provides a number of chat based models, including those Anthropic’s Claude.\n\n\n\n\n\n\n\n\nAWS credentials\n\n\n\nConsider using the approach outlined in this guide to manage your AWS credentials: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatBedrockAnthropic, requires the anthropic package with the bedrock extras (e.g., pip install anthropic[bedrock]).\n\n\n\n\n\nfrom chatlas import ChatBedrockAnthropic\n\nchat = ChatBedrockAnthropic(\n aws_profile=\"...\",\n aws_region=\"us-east\",\n aws_secret_key=\"...\",\n aws_access_key=\"...\",\n aws_session_token=\"...\",\n)\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\naws_secret_key\nOptional[str]\nThe AWS secret key to use for authentication.\nNone\n\n\naws_access_key\nOptional[str]\nThe AWS access key to use for authentication.\nNone\n\n\naws_region\nOptional[str]\nThe AWS region to use. Defaults to the AWS_REGION environment variable. If that is not set, defaults to 'us-east-1'.\nNone\n\n\naws_profile\nOptional[str]\nThe AWS profile to use.\nNone\n\n\naws_session_token\nOptional[str]\nThe AWS session token to use.\nNone\n\n\nbase_url\nOptional[str]\nThe base URL to use. Defaults to the ANTHROPIC_BEDROCK_BASE_URL environment variable. If that is not set, defaults to f\"https://bedrock-runtime.{aws_region}.amazonaws.com\".\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nkwargs\nOptional['ChatBedrockClientArgs']\nAdditional arguments to pass to the anthropic.AnthropicBedrock() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatBedrockAnthropic" ] }, { - "objectID": "reference/ChatGroq.html#note-1", - "href": "reference/ChatGroq.html#note-1", - "title": "ChatGroq", + "objectID": "reference/ChatBedrockAnthropic.html#prerequisites", + "href": "reference/ChatBedrockAnthropic.html#prerequisites", + "title": "ChatBedrockAnthropic", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatGroq(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGROQ_API_KEY=...\nfrom chatlas import ChatGroq\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGroq()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GROQ_API_KEY=...", + "text": "AWS credentials\n\n\n\nConsider using the approach outlined in this guide to manage your AWS credentials: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatBedrockAnthropic, requires the anthropic package with the bedrock extras (e.g., pip install anthropic[bedrock]).", "crumbs": [ "Reference", "Chat model providers", - "ChatGroq" + "ChatBedrockAnthropic" ] }, { - "objectID": "reference/types.ContentToolResult.html", - "href": "reference/types.ContentToolResult.html", - "title": "types.ContentToolResult", + "objectID": "reference/ChatBedrockAnthropic.html#examples", + "href": "reference/ChatBedrockAnthropic.html#examples", + "title": "ChatBedrockAnthropic", "section": "", - "text": "types.ContentToolResult(self, id, value=None, error=None)\nThe result of calling a tool/function\nThis content type isn’t meant to be used directly. Instead, it’s automatically generated by Chat when a tool/function is called (in response to a ContentToolRequest).\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nThe unique identifier of the tool request.\nrequired\n\n\nvalue\nAny\nThe value returned by the tool/function.\nNone\n\n\nerror\nOptional[str]\nAn error message if the tool/function call failed.\nNone", + "text": "from chatlas import ChatBedrockAnthropic\n\nchat = ChatBedrockAnthropic(\n aws_profile=\"...\",\n aws_region=\"us-east\",\n aws_secret_key=\"...\",\n aws_access_key=\"...\",\n aws_session_token=\"...\",\n)\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", - "User-facing types", - "types.ContentToolResult" + "Chat model providers", + "ChatBedrockAnthropic" ] }, { - "objectID": "reference/types.ContentToolResult.html#parameters", - "href": "reference/types.ContentToolResult.html#parameters", - "title": "types.ContentToolResult", + "objectID": "reference/ChatBedrockAnthropic.html#parameters", + "href": "reference/ChatBedrockAnthropic.html#parameters", + "title": "ChatBedrockAnthropic", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nid\nstr\nThe unique identifier of the tool request.\nrequired\n\n\nvalue\nAny\nThe value returned by the tool/function.\nNone\n\n\nerror\nOptional[str]\nAn error message if the tool/function call failed.\nNone", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nmodel\nOptional[str]\nThe model to use for the chat.\nNone\n\n\nmax_tokens\nint\nMaximum number of tokens to generate before stopping.\n4096\n\n\naws_secret_key\nOptional[str]\nThe AWS secret key to use for authentication.\nNone\n\n\naws_access_key\nOptional[str]\nThe AWS access key to use for authentication.\nNone\n\n\naws_region\nOptional[str]\nThe AWS region to use. Defaults to the AWS_REGION environment variable. If that is not set, defaults to 'us-east-1'.\nNone\n\n\naws_profile\nOptional[str]\nThe AWS profile to use.\nNone\n\n\naws_session_token\nOptional[str]\nThe AWS session token to use.\nNone\n\n\nbase_url\nOptional[str]\nThe base URL to use. Defaults to the ANTHROPIC_BEDROCK_BASE_URL environment variable. If that is not set, defaults to f\"https://bedrock-runtime.{aws_region}.amazonaws.com\".\nNone\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nkwargs\nOptional['ChatBedrockClientArgs']\nAdditional arguments to pass to the anthropic.AnthropicBedrock() client constructor.\nNone", "crumbs": [ "Reference", - "User-facing types", - "types.ContentToolResult" + "Chat model providers", + "ChatBedrockAnthropic" ] }, { - "objectID": "reference/index.html", - "href": "reference/index.html", - "title": "Function reference", + "objectID": "reference/ChatBedrockAnthropic.html#returns", + "href": "reference/ChatBedrockAnthropic.html#returns", + "title": "ChatBedrockAnthropic", "section": "", - "text": "Start a chat with a particular large language model (llm) provider.\n\n\n\nChatAnthropic\nChat with an Anthropic Claude model.\n\n\nChatAzureOpenAI\nChat with a model hosted on Azure OpenAI.\n\n\nChatBedrockAnthropic\nChat with an AWS bedrock model.\n\n\nChatGithub\nChat with a model hosted on the GitHub model marketplace.\n\n\nChatGoogle\nChat with a Google Gemini model.\n\n\nChatGroq\nChat with a model hosted on Groq.\n\n\nChatOllama\nChat with a local Ollama model.\n\n\nChatOpenAI\nChat with an OpenAI model.\n\n\nChatPerplexity\nChat with a model hosted on perplexity.ai.\n\n\n\n\n\n\nMethods and attributes available on a chat instance\n\n\n\nChat\nA chat object that can be used to interact with a language model.\n\n\n\n\n\n\nSubmit image input to the chat\n\n\n\ncontent_image_file\nEncode image content from a file for chat input.\n\n\ncontent_image_plot\nEncode the current matplotlib plot as an image for chat input.\n\n\ncontent_image_url\nEncode image content from a URL for chat input.\n\n\n\n\n\n\nInterpolate variables into prompt templates\n\n\n\ninterpolate\nInterpolate variables into a prompt\n\n\ninterpolate_file\nInterpolate variables into a prompt from a file\n\n\n\n\n\n\nAdd context to python function before registering it as a tool.\n\n\n\nTool\nDefine a tool\n\n\n\n\n\n\nA provider-agnostic representation of content generated during an assistant/user turn.\n\n\n\nTurn\nA user or assistant turn\n\n\n\n\n\n\n\n\n\ntoken_usage\nReport on token usage in the current session\n\n\n\n\n\n\n\n\n\nProvider\nA model provider interface for a Chat.\n\n\n\n\n\n\n\n\n\ntypes.Content\nBase class for all content types that can be appear in a Turn\n\n\ntypes.ContentImage\nBase class for image content.\n\n\ntypes.ContentImageInline\nInline image content.\n\n\ntypes.ContentImageRemote\nImage content from a URL.\n\n\ntypes.ContentJson\nJSON content\n\n\ntypes.ContentText\nText content for a Turn\n\n\ntypes.ContentToolRequest\nA request to call a tool/function\n\n\ntypes.ContentToolResult\nThe result of calling a tool/function\n\n\ntypes.ChatResponse\nChat response object.\n\n\ntypes.ChatResponseAsync\nChat response (async) object.\n\n\ntypes.ImageContentTypes\nAllowable content types for images.\n\n\ntypes.MISSING_TYPE\nA singleton representing a missing value.\n\n\ntypes.MISSING\n\n\n\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat()\n\n\ntypes.TokenUsage\nToken usage for a given provider (name).", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", "crumbs": [ "Reference", - "Function reference" + "Chat model providers", + "ChatBedrockAnthropic" ] }, { - "objectID": "reference/index.html#chat-model-providers", - "href": "reference/index.html#chat-model-providers", - "title": "Function reference", + "objectID": "reference/image_file.html", + "href": "reference/image_file.html", + "title": "content_image_file", "section": "", - "text": "Start a chat with a particular large language model (llm) provider.\n\n\n\nChatAnthropic\nChat with an Anthropic Claude model.\n\n\nChatAzureOpenAI\nChat with a model hosted on Azure OpenAI.\n\n\nChatBedrockAnthropic\nChat with an AWS bedrock model.\n\n\nChatGithub\nChat with a model hosted on the GitHub model marketplace.\n\n\nChatGoogle\nChat with a Google Gemini model.\n\n\nChatGroq\nChat with a model hosted on Groq.\n\n\nChatOllama\nChat with a local Ollama model.\n\n\nChatOpenAI\nChat with an OpenAI model.\n\n\nChatPerplexity\nChat with a model hosted on perplexity.ai.", - "crumbs": [ - "Reference", - "Function reference" - ] + "text": "content_image_file(path, content_type='auto', resize='low')\nEncode image content from a file for chat input.\nThis function is used to prepare image files for input to the chatbot. It can handle various image formats and provides options for resizing.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[str, Literal['none', 'low', 'high']]\nResizing option for the image. Can be: - \"none\": No resizing - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\n'low'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid." }, { - "objectID": "reference/index.html#the-chat-object", - "href": "reference/index.html#the-chat-object", - "title": "Function reference", + "objectID": "reference/image_file.html#parameters", + "href": "reference/image_file.html#parameters", + "title": "content_image_file", "section": "", - "text": "Methods and attributes available on a chat instance\n\n\n\nChat\nA chat object that can be used to interact with a language model.", - "crumbs": [ - "Reference", - "Function reference" - ] + "text": "Name\nType\nDescription\nDefault\n\n\n\n\npath\nstr\nThe path to the image file to include in the chat input.\nrequired\n\n\ncontent_type\nLiteral['auto', ImageContentTypes]\nThe content type of the image (e.g., \"image/png\"). If \"auto\", the content type is inferred from the file extension.\n'auto'\n\n\nresize\nUnion[str, Literal['none', 'low', 'high']]\nResizing option for the image. Can be: - \"none\": No resizing - \"low\": Resize to fit within 512x512 - \"high\": Resize to fit within 2000x768 or 768x2000 - Custom string (e.g., \"200x200\", \"300x200>!\", etc.)\n'low'" }, { - "objectID": "reference/index.html#image-input", - "href": "reference/index.html#image-input", - "title": "Function reference", + "objectID": "reference/image_file.html#returns", + "href": "reference/image_file.html#returns", + "title": "content_image_file", "section": "", - "text": "Submit image input to the chat\n\n\n\ncontent_image_file\nEncode image content from a file for chat input.\n\n\ncontent_image_plot\nEncode the current matplotlib plot as an image for chat input.\n\n\ncontent_image_url\nEncode image content from a URL for chat input.", - "crumbs": [ - "Reference", - "Function reference" - ] + "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." }, { - "objectID": "reference/index.html#prompt-interpolation", - "href": "reference/index.html#prompt-interpolation", - "title": "Function reference", + "objectID": "reference/image_file.html#examples", + "href": "reference/image_file.html#examples", + "title": "content_image_file", "section": "", - "text": "Interpolate variables into prompt templates\n\n\n\ninterpolate\nInterpolate variables into a prompt\n\n\ninterpolate_file\nInterpolate variables into a prompt from a file", - "crumbs": [ - "Reference", - "Function reference" - ] + "text": "from chatlas import ChatOpenAI, content_image_file\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_file(\"path/to/image.png\"),\n)" }, { - "objectID": "reference/index.html#tool-calling", - "href": "reference/index.html#tool-calling", - "title": "Function reference", + "objectID": "reference/image_file.html#raises", + "href": "reference/image_file.html#raises", + "title": "content_image_file", "section": "", - "text": "Add context to python function before registering it as a tool.\n\n\n\nTool\nDefine a tool", - "crumbs": [ - "Reference", - "Function reference" - ] + "text": "Name\nType\nDescription\n\n\n\n\n\nFileNotFoundError\nIf the specified file does not exist.\n\n\n\nValueError\nIf the file extension is unsupported or the resize option is invalid." }, { - "objectID": "reference/index.html#turns", - "href": "reference/index.html#turns", - "title": "Function reference", + "objectID": "reference/types.MISSING_TYPE.html", + "href": "reference/types.MISSING_TYPE.html", + "title": "types.MISSING_TYPE", "section": "", - "text": "A provider-agnostic representation of content generated during an assistant/user turn.\n\n\n\nTurn\nA user or assistant turn", + "text": "types.MISSING_TYPE\ntypes.MISSING_TYPE()\nA singleton representing a missing value.", "crumbs": [ "Reference", - "Function reference" + "User-facing types", + "types.MISSING_TYPE" ] }, { - "objectID": "reference/index.html#query-token-usage", - "href": "reference/index.html#query-token-usage", - "title": "Function reference", + "objectID": "reference/ChatPerplexity.html", + "href": "reference/ChatPerplexity.html", + "title": "ChatPerplexity", "section": "", - "text": "token_usage\nReport on token usage in the current session", + "text": "ChatPerplexity(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n base_url='https://api.perplexity.ai/',\n seed=MISSING,\n kwargs=None,\n)\nChat with a model hosted on perplexity.ai.\nPerplexity AI is a platform for running LLMs that are capable of searching the web in real-time to help them answer questions with information that may not have been available when the model was trained.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nSign up at https://www.perplexity.ai to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatPerplexity requires the openai package (e.g., pip install openai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatPerplexity\n\nchat = ChatPerplexity(api_key=os.getenv(\"PERPLEXITY_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the PERPLEXITY_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Perplexity’s API.\n'https://api.perplexity.ai/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.\n\n\n\n\n\n\nThis function is a lightweight wrapper around chatlas.ChatOpenAI with the defaults tweaked for perplexity.ai.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatPerplexity(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nPERPLEXITY_API_KEY=...\nfrom chatlas import ChatPerplexity\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatPerplexity()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport PERPLEXITY_API_KEY=...", "crumbs": [ "Reference", - "Function reference" + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/index.html#implement-a-model-provider", - "href": "reference/index.html#implement-a-model-provider", - "title": "Function reference", + "objectID": "reference/ChatPerplexity.html#prerequisites", + "href": "reference/ChatPerplexity.html#prerequisites", + "title": "ChatPerplexity", "section": "", - "text": "Provider\nA model provider interface for a Chat.", + "text": "API key\n\n\n\nSign up at https://www.perplexity.ai to get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatPerplexity requires the openai package (e.g., pip install openai).", "crumbs": [ "Reference", - "Function reference" + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/index.html#user-facing-types", - "href": "reference/index.html#user-facing-types", - "title": "Function reference", + "objectID": "reference/ChatPerplexity.html#examples", + "href": "reference/ChatPerplexity.html#examples", + "title": "ChatPerplexity", "section": "", - "text": "types.Content\nBase class for all content types that can be appear in a Turn\n\n\ntypes.ContentImage\nBase class for image content.\n\n\ntypes.ContentImageInline\nInline image content.\n\n\ntypes.ContentImageRemote\nImage content from a URL.\n\n\ntypes.ContentJson\nJSON content\n\n\ntypes.ContentText\nText content for a Turn\n\n\ntypes.ContentToolRequest\nA request to call a tool/function\n\n\ntypes.ContentToolResult\nThe result of calling a tool/function\n\n\ntypes.ChatResponse\nChat response object.\n\n\ntypes.ChatResponseAsync\nChat response (async) object.\n\n\ntypes.ImageContentTypes\nAllowable content types for images.\n\n\ntypes.MISSING_TYPE\nA singleton representing a missing value.\n\n\ntypes.MISSING\n\n\n\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat()\n\n\ntypes.TokenUsage\nToken usage for a given provider (name).", + "text": "import os\nfrom chatlas import ChatPerplexity\n\nchat = ChatPerplexity(api_key=os.getenv(\"PERPLEXITY_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", "crumbs": [ "Reference", - "Function reference" + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/image_url.html", - "href": "reference/image_url.html", - "title": "content_image_url", - "section": "", - "text": "content_image_url(url, detail='auto')\nEncode image content from a URL for chat input.\nThis function is used to prepare image URLs for input to the chatbot. It can handle both regular URLs and data URLs.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid." - }, - { - "objectID": "reference/image_url.html#parameters", - "href": "reference/image_url.html#parameters", - "title": "content_image_url", - "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'" - }, - { - "objectID": "reference/image_url.html#returns", - "href": "reference/image_url.html#returns", - "title": "content_image_url", - "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." - }, - { - "objectID": "reference/image_url.html#examples", - "href": "reference/image_url.html#examples", - "title": "content_image_url", - "section": "", - "text": "from chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)" - }, - { - "objectID": "reference/image_url.html#raises", - "href": "reference/image_url.html#raises", - "title": "content_image_url", + "objectID": "reference/ChatPerplexity.html#parameters", + "href": "reference/ChatPerplexity.html#parameters", + "title": "ChatPerplexity", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid." + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the PERPLEXITY_API_KEY environment variable.\nNone\n\n\nbase_url\nstr\nThe base URL to the endpoint; the default uses Perplexity’s API.\n'https://api.perplexity.ai/'\n\n\nseed\nOptional[int] | MISSING_TYPE\nOptional integer seed that ChatGPT uses to try and make output more reproducible.\nMISSING\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the openai.OpenAI() client constructor.\nNone", + "crumbs": [ + "Reference", + "Chat model providers", + "ChatPerplexity" + ] }, { - "objectID": "reference/types.Content.html", - "href": "reference/types.Content.html", - "title": "types.Content", + "objectID": "reference/ChatPerplexity.html#returns", + "href": "reference/ChatPerplexity.html#returns", + "title": "ChatPerplexity", "section": "", - "text": "types.Content\ntypes.Content()\nBase class for all content types that can be appear in a Turn", + "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA chat object that retains the state of the conversation.", "crumbs": [ "Reference", - "User-facing types", - "types.Content" + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/token_usage.html", - "href": "reference/token_usage.html", - "title": "token_usage", + "objectID": "reference/ChatPerplexity.html#note", + "href": "reference/ChatPerplexity.html#note", + "title": "ChatPerplexity", "section": "", - "text": "token_usage()\nReport on token usage in the current session\nCall this function to find out the cumulative number of tokens that you have sent and received in the current session.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nlist[TokenUsage] | None\nA list of dictionaries with the following keys: “name”, “input”, and “output”. If no tokens have been logged, then None is returned.", + "text": "This function is a lightweight wrapper around chatlas.ChatOpenAI with the defaults tweaked for perplexity.ai.", "crumbs": [ - "Reference", - "Query token usage", - "token_usage" + "Reference", + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/token_usage.html#returns", - "href": "reference/token_usage.html#returns", - "title": "token_usage", + "objectID": "reference/ChatPerplexity.html#note-1", + "href": "reference/ChatPerplexity.html#note-1", + "title": "ChatPerplexity", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nlist[TokenUsage] | None\nA list of dictionaries with the following keys: “name”, “input”, and “output”. If no tokens have been logged, then None is returned.", + "text": "Pasting an API key into a chat constructor (e.g., ChatPerplexity(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nPERPLEXITY_API_KEY=...\nfrom chatlas import ChatPerplexity\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatPerplexity()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport PERPLEXITY_API_KEY=...", "crumbs": [ "Reference", - "Query token usage", - "token_usage" + "Chat model providers", + "ChatPerplexity" ] }, { - "objectID": "reference/types.ContentJson.html", - "href": "reference/types.ContentJson.html", - "title": "types.ContentJson", + "objectID": "reference/types.ImageContentTypes.html", + "href": "reference/types.ImageContentTypes.html", + "title": "types.ImageContentTypes", "section": "", - "text": "types.ContentJson(self, value)\nJSON content\nThis content type primarily exists to signal structured data extraction (i.e., data extracted via Chat’s .extract_data() method)\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nvalue\ndict[str, Any]\nThe JSON data extracted\nrequired", + "text": "types.ImageContentTypes\ntypes.ImageContentTypes\nAllowable content types for images.", "crumbs": [ "Reference", "User-facing types", - "types.ContentJson" + "types.ImageContentTypes" ] }, { - "objectID": "reference/types.ContentJson.html#parameters", - "href": "reference/types.ContentJson.html#parameters", - "title": "types.ContentJson", + "objectID": "reference/types.ContentImage.html", + "href": "reference/types.ContentImage.html", + "title": "types.ContentImage", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nvalue\ndict[str, Any]\nThe JSON data extracted\nrequired", + "text": "types.ContentImage\ntypes.ContentImage()\nBase class for image content.\nThis class is not meant to be used directly. Instead, use content_image_url, content_image_file, or content_image_plot.", "crumbs": [ "Reference", "User-facing types", - "types.ContentJson" + "types.ContentImage" ] }, { - "objectID": "reference/image_plot.html", - "href": "reference/image_plot.html", - "title": "content_image_plot", - "section": "", - "text": "content_image_plot(width=768, height=768, dpi=72)\nEncode the current matplotlib plot as an image for chat input.\nThis function captures the current matplotlib plot, resizes it to the specified dimensions, and prepares it for chat input.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)" - }, - { - "objectID": "reference/image_plot.html#parameters", - "href": "reference/image_plot.html#parameters", - "title": "content_image_plot", - "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nwidth\nint\nThe desired width of the output image in pixels.\n768\n\n\nheight\nint\nThe desired height of the output image in pixels.\n768\n\n\ndpi\nint\nThe DPI (dots per inch) of the output image.\n72" - }, - { - "objectID": "reference/image_plot.html#returns", - "href": "reference/image_plot.html#returns", - "title": "content_image_plot", + "objectID": "reference/types.TokenUsage.html", + "href": "reference/types.TokenUsage.html", + "title": "types.TokenUsage", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object." + "text": "types.TokenUsage\ntypes.TokenUsage()\nToken usage for a given provider (name).", + "crumbs": [ + "Reference", + "User-facing types", + "types.TokenUsage" + ] }, { - "objectID": "reference/image_plot.html#raises", - "href": "reference/image_plot.html#raises", - "title": "content_image_plot", + "objectID": "reference/interpolate.html", + "href": "reference/interpolate.html", + "title": "interpolate", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf width or height is not a positive integer." + "text": "interpolate(prompt, *, variables=None, variable_start='{{', variable_end='}}')\nInterpolate variables into a prompt\nThis is a light-weight wrapper around the Jinja2 templating engine, making it easier to interpolate dynamic data into a prompt template. Compared to f-strings, which expects you to wrap dynamic values in { }, this function expects { } instead, making it easier to include Python code and JSON in your prompt.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nprompt\nstr\nThe prompt to interpolate (as a string).\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.\n\n\n\n\n\n\nfrom chatlas import interpolate\n\nx = 1\ninterpolate(\"The value of `x` is: {{ x }}\")", + "crumbs": [ + "Reference", + "Prompt interpolation", + "interpolate" + ] }, { - "objectID": "reference/image_plot.html#examples", - "href": "reference/image_plot.html#examples", - "title": "content_image_plot", + "objectID": "reference/interpolate.html#parameters", + "href": "reference/interpolate.html#parameters", + "title": "interpolate", "section": "", - "text": "from chatlas import ChatOpenAI, content_image_plot\nimport matplotlib.pyplot as plt\n\nplt.scatter(faithful[\"eruptions\"], faithful[\"waiting\"])\nchat = ChatOpenAI()\nchat.chat(\n \"Describe this plot in one paragraph, as suitable for inclusion in \"\n \"alt-text. You should briefly describe the plot type, the axes, and \"\n \"2-5 major visual patterns.\",\n content_image_plot(),\n)" + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nprompt\nstr\nThe prompt to interpolate (as a string).\nrequired\n\n\nvariables\nOptional[dict[str, Any]]\nA dictionary of variables to interpolate into the prompt. If not provided, the caller’s global and local variables are used.\nNone\n\n\nvariable_start\nstr\nThe string that marks the beginning of a variable.\n'{{'\n\n\nvariable_end\nstr\nThe string that marks the end of a variable.\n'}}'", + "crumbs": [ + "Reference", + "Prompt interpolation", + "interpolate" + ] }, { - "objectID": "reference/types.ContentImageInline.html", - "href": "reference/types.ContentImageInline.html", - "title": "types.ContentImageInline", + "objectID": "reference/interpolate.html#returns", + "href": "reference/interpolate.html#returns", + "title": "interpolate", "section": "", - "text": "types.ContentImageInline(self, content_type, data=None)\nInline image content.\nThis is the return type for content_image_file and content_image_plot. It’s not meant to be used directly.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ncontent_type\nImageContentTypes\nThe content type of the image.\nrequired\n\n\ndata\nOptional[str]\nThe base64-encoded image data.\nNone", + "text": "Name\nType\nDescription\n\n\n\n\n\nstr\nThe prompt with variables interpolated.", "crumbs": [ "Reference", - "User-facing types", - "types.ContentImageInline" + "Prompt interpolation", + "interpolate" ] }, { - "objectID": "reference/types.ContentImageInline.html#parameters", - "href": "reference/types.ContentImageInline.html#parameters", - "title": "types.ContentImageInline", + "objectID": "reference/interpolate.html#examples", + "href": "reference/interpolate.html#examples", + "title": "interpolate", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\ncontent_type\nImageContentTypes\nThe content type of the image.\nrequired\n\n\ndata\nOptional[str]\nThe base64-encoded image data.\nNone", + "text": "from chatlas import interpolate\n\nx = 1\ninterpolate(\"The value of `x` is: {{ x }}\")", "crumbs": [ "Reference", - "User-facing types", - "types.ContentImageInline" + "Prompt interpolation", + "interpolate" ] }, { - "objectID": "reference/content_image_url.html", - "href": "reference/content_image_url.html", - "title": "content_image_url", + "objectID": "reference/types.ChatResponse.html", + "href": "reference/types.ChatResponse.html", + "title": "types.ChatResponse", "section": "", - "text": "content_image_url(url, detail='auto')\nEncode image content from a URL for chat input.\nThis function is used to prepare image URLs for input to the chatbot. It can handle both regular URLs and data URLs.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.\n\n\n\n\n\n\nfrom chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid.", + "text": "types.ChatResponse(self, generator)\nChat response object.\nAn object that, when displayed, will simulatenously consume (if not already consumed) and display the response in a streaming fashion.\nThis is useful for interactive use: if the object is displayed, it can be viewed as it is being generated. And, if the object is not displayed, it can act like an iterator that can be consumed by something else.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.\n\n\n\n\n\n\nconsumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).\n\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponse.get_content()\nGet the chat response content as a string.", "crumbs": [ "Reference", - "Image input", - "content_image_url" + "User-facing types", + "types.ChatResponse" ] }, { - "objectID": "reference/content_image_url.html#parameters", - "href": "reference/content_image_url.html#parameters", - "title": "content_image_url", + "objectID": "reference/types.ChatResponse.html#attributes", + "href": "reference/types.ChatResponse.html#attributes", + "title": "types.ChatResponse", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nurl\nstr\nThe URL of the image to include in the chat input. Can be a data: URL or a regular URL.\nrequired\n\n\ndetail\nLiteral['auto', 'low', 'high']\nThe detail setting for this image. Can be \"auto\", \"low\", or \"high\".\n'auto'", + "text": "Name\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.", "crumbs": [ "Reference", - "Image input", - "content_image_url" + "User-facing types", + "types.ChatResponse" ] }, { - "objectID": "reference/content_image_url.html#returns", - "href": "reference/content_image_url.html#returns", - "title": "content_image_url", + "objectID": "reference/types.ChatResponse.html#properties", + "href": "reference/types.ChatResponse.html#properties", + "title": "types.ChatResponse", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\n[](~chatlas.types.Content)\nContent suitable for a Turn object.", + "text": "consumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).", "crumbs": [ "Reference", - "Image input", - "content_image_url" + "User-facing types", + "types.ChatResponse" ] }, { - "objectID": "reference/content_image_url.html#examples", - "href": "reference/content_image_url.html#examples", - "title": "content_image_url", + "objectID": "reference/types.ChatResponse.html#methods", + "href": "reference/types.ChatResponse.html#methods", + "title": "types.ChatResponse", "section": "", - "text": "from chatlas import ChatOpenAI, content_image_url\n\nchat = ChatOpenAI()\nchat.chat(\n \"What do you see in this image?\",\n content_image_url(\"https://www.python.org/static/img/python-logo.png\"),\n)", + "text": "Name\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponse.get_content()\nGet the chat response content as a string.", "crumbs": [ "Reference", - "Image input", - "content_image_url" + "User-facing types", + "types.ChatResponse" ] }, { - "objectID": "reference/content_image_url.html#raises", - "href": "reference/content_image_url.html#raises", - "title": "content_image_url", + "objectID": "reference/Tool.html", + "href": "reference/Tool.html", + "title": "Tool", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nValueError\nIf the URL is not valid or the detail setting is invalid.", + "text": "Tool(self, func, *, model=None)\nDefine a tool\nDefine a Python function for use by a chatbot. The function will always be invoked in the current Python process.\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfunc\nCallable[…, Any] | Callable[…, Awaitable[Any]]\nThe function to be invoked when the tool is called.\nrequired\n\n\nmodel\nOptional[type[BaseModel]]\nA Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\nNone", "crumbs": [ "Reference", - "Image input", - "content_image_url" + "Tool calling", + "Tool" ] }, { - "objectID": "reference/ChatGoogle.html", - "href": "reference/ChatGoogle.html", - "title": "ChatGoogle", + "objectID": "reference/Tool.html#parameters", + "href": "reference/Tool.html#parameters", + "title": "Tool", "section": "", - "text": "ChatGoogle(\n system_prompt=None,\n turns=None,\n model=None,\n api_key=None,\n kwargs=None,\n)\nChat with a Google Gemini model.\n\n\n\n\n\n\n\n\nAPI key\n\n\n\nTo use Google’s models (i.e., Gemini), you’ll need to sign up for an account and get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGoogle requires the google-generativeai package (e.g., pip install google-generativeai).\n\n\n\n\n\nimport os\nfrom chatlas import ChatGoogle\n\nchat = ChatGoogle(api_key=os.getenv(\"GOOGLE_API_KEY\"))\nchat.chat(\"What is the capital of France?\")\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GOOGLE_API_KEY environment variable.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the genai.GenerativeModel constructor.\nNone\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.\n\n\n\n\n\n\nChatGoogle currently doesn’t work with streaming tools.\n\n\n\nPasting an API key into a chat constructor (e.g., ChatGoogle(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGOOGLE_API_KEY=...\nfrom chatlas import ChatGoogle\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGoogle()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GOOGLE_API_KEY=...", + "text": "Name\nType\nDescription\nDefault\n\n\n\n\nfunc\nCallable[…, Any] | Callable[…, Awaitable[Any]]\nThe function to be invoked when the tool is called.\nrequired\n\n\nmodel\nOptional[type[BaseModel]]\nA Pydantic model that describes the input parameters for the function. If not provided, the model will be inferred from the function’s type hints. The primary reason why you might want to provide a model in Note that the name and docstring of the model takes precedence over the name and docstring of the function.\nNone", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "Tool calling", + "Tool" ] }, { - "objectID": "reference/ChatGoogle.html#prerequisites", - "href": "reference/ChatGoogle.html#prerequisites", - "title": "ChatGoogle", + "objectID": "reference/types.SubmitInputArgsT.html", + "href": "reference/types.SubmitInputArgsT.html", + "title": "types.SubmitInputArgsT", "section": "", - "text": "API key\n\n\n\nTo use Google’s models (i.e., Gemini), you’ll need to sign up for an account and get an API key.\n\n\n\n\n\n\n\n\nPython requirements\n\n\n\nChatGoogle requires the google-generativeai package (e.g., pip install google-generativeai).", + "text": "types.SubmitInputArgsT\ntypes.SubmitInputArgsT\nA TypedDict representing the arguments that can be passed to the .chat() method of a Chat instance.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "User-facing types", + "types.SubmitInputArgsT" ] }, { - "objectID": "reference/ChatGoogle.html#examples", - "href": "reference/ChatGoogle.html#examples", - "title": "ChatGoogle", + "objectID": "reference/Provider.html", + "href": "reference/Provider.html", + "title": "Provider", "section": "", - "text": "import os\nfrom chatlas import ChatGoogle\n\nchat = ChatGoogle(api_key=os.getenv(\"GOOGLE_API_KEY\"))\nchat.chat(\"What is the capital of France?\")", + "text": "Provider\nProvider()\nA model provider interface for a Chat.\nThis abstract class defines the interface a model provider must implement in order to be used with a Chat instance. The provider is responsible for performing the actual chat completion, and for handling the streaming of the completion results.\nNote that this class is exposed for developers who wish to implement their own provider. In general, you should not need to interact with this class directly.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "Implement a model provider", + "Provider" ] }, { - "objectID": "reference/ChatGoogle.html#parameters", - "href": "reference/ChatGoogle.html#parameters", - "title": "ChatGoogle", + "objectID": "reference/types.ChatResponseAsync.html", + "href": "reference/types.ChatResponseAsync.html", + "title": "types.ChatResponseAsync", "section": "", - "text": "Name\nType\nDescription\nDefault\n\n\n\n\nsystem_prompt\nOptional[str]\nA system prompt to set the behavior of the assistant.\nNone\n\n\nturns\nOptional[list[Turn]]\nA list of turns to start the chat with (i.e., continuing a previous conversation). If not provided, the conversation begins from scratch. Do not provide non-None values for both turns and system_prompt. Each message in the list should be a dictionary with at least role (usually system, user, or assistant, but tool is also possible). Normally there is also a content field, which is a string.\nNone\n\n\nmodel\nOptional[str]\nThe model to use for the chat. The default, None, will pick a reasonable default, and warn you about it. We strongly recommend explicitly choosing a model for all but the most casual use.\nNone\n\n\napi_key\nOptional[str]\nThe API key to use for authentication. You generally should not supply this directly, but instead set the GOOGLE_API_KEY environment variable.\nNone\n\n\nkwargs\nOptional['ChatClientArgs']\nAdditional arguments to pass to the genai.GenerativeModel constructor.\nNone", + "text": "types.ChatResponseAsync(self, generator)\nChat response (async) object.\nAn object that, when displayed, will simulatenously consume (if not already consumed) and display the response in a streaming fashion.\nThis is useful for interactive use: if the object is displayed, it can be viewed as it is being generated. And, if the object is not displayed, it can act like an iterator that can be consumed by something else.\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.\n\n\n\n\n\n\nconsumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).\n\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponseAsync.get_content()\nGet the chat response content as a string.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "User-facing types", + "types.ChatResponseAsync" ] }, { - "objectID": "reference/ChatGoogle.html#returns", - "href": "reference/ChatGoogle.html#returns", - "title": "ChatGoogle", + "objectID": "reference/types.ChatResponseAsync.html#attributes", + "href": "reference/types.ChatResponseAsync.html#attributes", + "title": "types.ChatResponseAsync", "section": "", - "text": "Name\nType\nDescription\n\n\n\n\n\nChat\nA Chat object.", + "text": "Name\nType\nDescription\n\n\n\n\ncontent\nstr\nThe content of the chat response.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "User-facing types", + "types.ChatResponseAsync" ] }, { - "objectID": "reference/ChatGoogle.html#limitations", - "href": "reference/ChatGoogle.html#limitations", - "title": "ChatGoogle", + "objectID": "reference/types.ChatResponseAsync.html#properties", + "href": "reference/types.ChatResponseAsync.html#properties", + "title": "types.ChatResponseAsync", "section": "", - "text": "ChatGoogle currently doesn’t work with streaming tools.", + "text": "consumed Whether the response has been consumed. If the response has been fully consumed, then it can no longer be iterated over, but the content can still be retrieved (via the content attribute).", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "User-facing types", + "types.ChatResponseAsync" ] }, { - "objectID": "reference/ChatGoogle.html#note", - "href": "reference/ChatGoogle.html#note", - "title": "ChatGoogle", + "objectID": "reference/types.ChatResponseAsync.html#methods", + "href": "reference/types.ChatResponseAsync.html#methods", + "title": "types.ChatResponseAsync", "section": "", - "text": "Pasting an API key into a chat constructor (e.g., ChatGoogle(api_key=\"...\")) is the simplest way to get started, and is fine for interactive use, but is problematic for code that may be shared with others.\nInstead, consider using environment variables or a configuration file to manage your credentials. One popular way to manage credentials is to use a .env file to store your credentials, and then use the python-dotenv package to load them into your environment.\npip install python-dotenv\n# .env\nGOOGLE_API_KEY=...\nfrom chatlas import ChatGoogle\nfrom dotenv import load_dotenv\n\nload_dotenv()\nchat = ChatGoogle()\nchat.console()\nAnother, more general, solution is to load your environment variables into the shell before starting Python (maybe in a .bashrc, .zshrc, etc. file):\nexport GOOGLE_API_KEY=...", + "text": "Name\nDescription\n\n\n\n\nget_content\nGet the chat response content as a string.\n\n\n\n\n\ntypes.ChatResponseAsync.get_content()\nGet the chat response content as a string.", "crumbs": [ "Reference", - "Chat model providers", - "ChatGoogle" + "User-facing types", + "types.ChatResponseAsync" ] } ] \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 43f2735..102dc57 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,179 +1,183 @@ - https://posit-dev.github.io/chatlas/reference/types.ChatResponseAsync.html - 2024-12-13T22:34:07.126Z + https://posit-dev.github.io/chatlas/rag.html + 2024-12-13T22:55:19.452Z - https://posit-dev.github.io/chatlas/reference/Provider.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/ChatGoogle.html + 2024-12-13T22:56:06.245Z - https://posit-dev.github.io/chatlas/reference/types.SubmitInputArgsT.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/content_image_url.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/Tool.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.ContentImageInline.html + 2024-12-13T22:56:06.349Z - https://posit-dev.github.io/chatlas/reference/types.ChatResponse.html - 2024-12-13T22:34:07.122Z + https://posit-dev.github.io/chatlas/reference/image_plot.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/interpolate.html - 2024-12-13T22:34:07.086Z + https://posit-dev.github.io/chatlas/reference/types.ContentJson.html + 2024-12-13T22:56:06.357Z - https://posit-dev.github.io/chatlas/reference/types.TokenUsage.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/token_usage.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/types.ContentImage.html - 2024-12-13T22:34:07.102Z + https://posit-dev.github.io/chatlas/reference/types.Content.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/types.ImageContentTypes.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/image_url.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/ChatPerplexity.html - 2024-12-13T22:34:07.022Z + https://posit-dev.github.io/chatlas/reference/index.html + 2024-12-13T22:56:06.201Z - https://posit-dev.github.io/chatlas/reference/types.MISSING_TYPE.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.ContentToolResult.html + 2024-12-13T22:56:06.361Z - https://posit-dev.github.io/chatlas/reference/image_file.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/ChatGroq.html + 2024-12-13T22:56:06.249Z - https://posit-dev.github.io/chatlas/reference/ChatBedrockAnthropic.html - 2024-12-13T22:34:06.986Z + https://posit-dev.github.io/chatlas/reference/types.ContentImageRemote.html + 2024-12-13T22:56:06.353Z - https://posit-dev.github.io/chatlas/reference/ChatOpenAI.html - 2024-12-13T22:34:07.014Z + https://posit-dev.github.io/chatlas/reference/types.MISSING.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/content_image_file.html - 2024-12-13T22:34:07.074Z + https://posit-dev.github.io/chatlas/reference/types.ContentText.html + 2024-12-13T22:56:06.357Z - https://posit-dev.github.io/chatlas/reference/ChatAnthropic.html - 2024-12-13T22:34:06.970Z + https://posit-dev.github.io/chatlas/reference/types.ContentToolRequest.html + 2024-12-13T22:56:06.361Z - https://posit-dev.github.io/chatlas/reference/interpolate_file.html - 2024-12-13T22:34:07.090Z + https://posit-dev.github.io/chatlas/reference/content_image_plot.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/Chat.html - 2024-12-13T22:34:07.070Z + https://posit-dev.github.io/chatlas/reference/Turn.html + 2024-12-13T22:56:06.341Z - https://posit-dev.github.io/chatlas/reference/ChatOllama.html - 2024-12-13T22:34:07.010Z + https://posit-dev.github.io/chatlas/reference/ChatAzureOpenAI.html + 2024-12-13T22:56:06.225Z - https://posit-dev.github.io/chatlas/web-apps.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/ChatGithub.html + 2024-12-13T22:56:06.237Z - https://posit-dev.github.io/chatlas/structured-data.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/get-started.html + 2024-12-13T22:55:19.448Z - https://posit-dev.github.io/chatlas/prompt-design.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/index.html + 2024-12-13T22:56:09.225Z https://posit-dev.github.io/chatlas/tool-calling.html - 2024-12-13T22:33:46.486Z + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/index.html - 2024-12-13T22:34:09.610Z + https://posit-dev.github.io/chatlas/prompt-design.html + 2024-12-13T22:55:19.452Z - https://posit-dev.github.io/chatlas/get-started.html - 2024-12-13T22:33:46.478Z + https://posit-dev.github.io/chatlas/structured-data.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/ChatGithub.html - 2024-12-13T22:34:06.994Z + https://posit-dev.github.io/chatlas/web-apps.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/ChatAzureOpenAI.html - 2024-12-13T22:34:06.978Z + https://posit-dev.github.io/chatlas/reference/ChatOllama.html + 2024-12-13T22:56:06.257Z - https://posit-dev.github.io/chatlas/reference/Turn.html - 2024-12-13T22:34:07.098Z + https://posit-dev.github.io/chatlas/reference/Chat.html + 2024-12-13T22:56:06.317Z - https://posit-dev.github.io/chatlas/reference/content_image_plot.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/interpolate_file.html + 2024-12-13T22:56:06.337Z - https://posit-dev.github.io/chatlas/reference/types.ContentToolRequest.html - 2024-12-13T22:34:07.114Z + https://posit-dev.github.io/chatlas/reference/ChatAnthropic.html + 2024-12-13T22:56:06.217Z - https://posit-dev.github.io/chatlas/reference/types.ContentText.html - 2024-12-13T22:34:07.110Z + https://posit-dev.github.io/chatlas/reference/content_image_file.html + 2024-12-13T22:56:06.321Z - https://posit-dev.github.io/chatlas/reference/types.MISSING.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/ChatOpenAI.html + 2024-12-13T22:56:06.261Z - https://posit-dev.github.io/chatlas/reference/types.ContentImageRemote.html - 2024-12-13T22:34:07.106Z + https://posit-dev.github.io/chatlas/reference/ChatBedrockAnthropic.html + 2024-12-13T22:56:06.233Z - https://posit-dev.github.io/chatlas/reference/ChatGroq.html - 2024-12-13T22:34:07.006Z + https://posit-dev.github.io/chatlas/reference/image_file.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/types.ContentToolResult.html - 2024-12-13T22:34:07.118Z + https://posit-dev.github.io/chatlas/reference/types.MISSING_TYPE.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/index.html - 2024-12-13T22:34:06.954Z + https://posit-dev.github.io/chatlas/reference/ChatPerplexity.html + 2024-12-13T22:56:06.269Z - https://posit-dev.github.io/chatlas/reference/image_url.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.ImageContentTypes.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/types.Content.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.ContentImage.html + 2024-12-13T22:56:06.349Z - https://posit-dev.github.io/chatlas/reference/token_usage.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.TokenUsage.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/types.ContentJson.html - 2024-12-13T22:34:07.110Z + https://posit-dev.github.io/chatlas/reference/interpolate.html + 2024-12-13T22:56:06.333Z - https://posit-dev.github.io/chatlas/reference/image_plot.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.ChatResponse.html + 2024-12-13T22:56:06.365Z - https://posit-dev.github.io/chatlas/reference/types.ContentImageInline.html - 2024-12-13T22:34:07.106Z + https://posit-dev.github.io/chatlas/reference/Tool.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/content_image_url.html - 2024-12-13T22:33:46.486Z + https://posit-dev.github.io/chatlas/reference/types.SubmitInputArgsT.html + 2024-12-13T22:55:19.456Z - https://posit-dev.github.io/chatlas/reference/ChatGoogle.html - 2024-12-13T22:34:06.998Z + https://posit-dev.github.io/chatlas/reference/Provider.html + 2024-12-13T22:55:19.456Z + + + https://posit-dev.github.io/chatlas/reference/types.ChatResponseAsync.html + 2024-12-13T22:56:06.369Z diff --git a/structured-data.html b/structured-data.html index 78c5b89..3834e1f 100644 --- a/structured-data.html +++ b/structured-data.html @@ -159,6 +159,10 @@
  • Build a chatbot +
  • +
  • + + Retrieval-Augmented Generation (RAG)
  • @@ -228,7 +232,7 @@

    Structured data

    When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like. This will generally work well most of the time, but there’s no guarantee that you’ll actually get the exact format that you want. In particular, if you’re trying to get JSON, find that it’s typically surrounded in ```json, and you’ll occassionally get text that isn’t actually valid JSON. To avoid these challenges you can use a recent LLM feature: structured data (aka structured output). With structured data, you supply a type specification that exactly defines the object structure that you want and the LLM will guarantee that’s what you get back.

    -
    +
    import json
     import pandas as pd
     from chatlas import ChatOpenAI
    @@ -237,7 +241,7 @@ 

    Structured data

    Structured data basics

    To extract structured data you call the .extract_data() method instead of the .chat() method. You’ll also need to define a type specification that describes the structure of the data that you want (more on that shortly). Here’s a simple example that extracts two specific values from a string:

    -
    +
    class Person(BaseModel):
         name: str
         age: int
    @@ -253,7 +257,7 @@ 

    Structured data bas

    The same basic idea works with images too:

    -
    +
    from chatlas import content_image_url
     
     class Image(BaseModel):
    @@ -265,7 +269,7 @@ 

    Structured data bas data_model=Image, )

    -
    {'primary_shape': 'oval and letter', 'primary_colour': 'gray and blue'}
    +
    {'primary_shape': "letter 'R' with an oval", 'primary_colour': 'blue and grey'}
    @@ -273,7 +277,7 @@

    Structured data bas

    Data types basics

    To define your desired type specification (also known as a schema), you use a pydantic model.

    In addition to the model definition with field names and types, you may also want to provide the LLM with an additional context about what each field/model represents. In this case, include a Field(description="...") for each field, and a docstring for each model. This is a good place to ask nicely for other attributes you’ll like the value to possess (e.g. minimum or maximum values, date formats, …). You aren’t guaranteed that these requests will be honoured, but the LLM will usually make a best effort to do so.

    -
    +
    class Person(BaseModel):
         """A person"""
     
    @@ -292,7 +296,7 @@ 

    Examples

    The following examples are closely inspired by the Claude documentation and hint at some of the ways you can use structured data extraction.

    Example 1: Article summarisation

    -
    +
    with open("examples/third-party-testing.txt") as f:
         text = f.read()
     
    @@ -322,24 +326,23 @@ 

    Example 1: print(json.dumps(data, indent=2))

    {
    -  "author": "N/A",
    +  "author": "Anthropic Team",
       "topics": [
         "AI policy",
         "third-party testing",
    -    "technology safety",
    -    "regulatory capture",
    -    "AI regulation"
    +    "regulation",
    +    "AI safety"
       ],
    -  "summary": "The article discusses the importance of implementing a robust third-party testing regime for frontier AI systems to ensure their safety and mitigate the risks of societal harm. It emphasizes the need for involvement from industry, government, and academia to develop standards and procedures for testing. Third-party testing is considered critical for addressing potential misuse or accidents associated with large-scale generative AI models. The article outlines the goals of developing an effective testing regime, which includes building trust, ensuring safety measures for powerful systems, and promoting coordination between countries. There is also discussion about balancing transparency and preventing harmful uses, as well as the potential for regulatory capture. Ultimately, this testing regime aims to complement sector-specific regulations and enable effective oversight of AI development.",
    -  "coherence": 85,
    -  "persuasion": 0.89
    +  "summary": "The article emphasizes the importance of implementing a third-party testing regime for AI systems, particularly large-scale generative models like Claude, ChatGPT, and Gemini. Given the transformative potential and risks of these AI systems, the authors argue for a comprehensive oversight framework involving industry, government, and academia. Current self-governance initiatives, like Anthropic's Responsible Scaling Policy, are seen as insufficient for industry-wide credibility. Therefore, creating broadly-trusted third-party testing and evaluation processes is crucial for validating AI safety, preventing misuse, and avoiding over-regulation. The authors advocate for initial experiments and government-backed testing infrastructures to iteratively develop an effective and fair system that minimizes accidents while ensuring competitiveness.",
    +  "coherence": 90,
    +  "persuasion": 0.85
     }

    Example 2: Named entity recognition

    -
    +
    text = "John works at Google in New York. He met with Sarah, the CEO of Acme Inc., last week in San Francisco."
     
     
    @@ -402,12 +405,18 @@ 

    Example 4 -Acme Inc. -organization +CEO +position He met with Sarah, the CEO of Acme Inc., last ... 5 +Acme Inc. +organization +He met with Sarah, the CEO of Acme Inc., last ... + + +6 San Francisco location He met with Sarah, the CEO of Acme Inc., last ... @@ -421,7 +430,7 @@

    Example

    Example 3: Sentiment analysis

    -
    +
    text = "The product was okay, but the customer service was terrible. I probably won't buy from them again."
     
     class Sentiment(BaseModel):
    @@ -443,14 +452,14 @@ 

    Example 3: Se chat = ChatOpenAI() chat.extract_data(text, data_model=Sentiment)

    -
    {'positive_score': 0.1, 'negative_score': 0.7, 'neutral_score': 0.2}
    +
    {'positive_score': 0.15, 'negative_score': 0.7, 'neutral_score': 0.15}

    Note that we’ve asked nicely for the scores to sum 1, and they do in this example (at least when I ran the code), but it’s not guaranteed.

    Example 4: Text classification

    -
    +
    from typing import Literal
     
     text = "The new quantum computing breakthrough could revolutionize the tech industry."
    @@ -490,17 +499,17 @@ 

    Example 4: T 0 Technology -0.7 +0.70 1 Business -0.2 +0.15 2 Other -0.1 +0.15 @@ -511,7 +520,7 @@

    Example 4: T

    Example 5: Working with unknown keys

    -
    +
    from chatlas import ChatAnthropic
     
     
    @@ -534,7 +543,7 @@ 

    Exampl print(json.dumps(data, indent=2))

    {
    -  "appearance": {
    +  "physical_characteristics": {
         "height": "tall",
         "facial_features": {
           "beard": true,
    @@ -542,12 +551,12 @@ 

    Exampl "location": "left cheek" } }, - "voice": "deep", - "clothing": { - "outerwear": { - "type": "leather jacket", - "color": "black" - } + "voice": "deep" + }, + "clothing": { + "outerwear": { + "type": "leather jacket", + "color": "black" } } }

    @@ -566,7 +575,7 @@

    Ex

    Even without any descriptions, ChatGPT does pretty well:

    -
    +
    from chatlas import content_image_file
     
     
    @@ -633,7 +642,7 @@ 

    Ex Rent 100001 1000000 -False +True @@ -650,7 +659,7 @@

    Advanced data typesRequired vs optional

    By default, model fields are in a sense “required”, unless None is allowed in their type definition. Including None is a good idea if there’s any possibility of the input not containing the required fields as LLMs may hallucinate data in order to fulfill your spec.

    For example, here the LLM hallucinates a date even though there isn’t one in the text:

    -
    +
    class ArticleSpec(BaseModel):
         """Information about an article written in markdown"""
     
    @@ -677,13 +686,13 @@ 

    Required vs optional<
    {
       "title": "Structured Data",
       "author": "Hadley Wickham",
    -  "date": "2023-10-07"
    +  "date": "2023-10-30"
     }

    Note that I’ve used more of an explict prompt here. For this example, I found that this generated better results, and it’s a useful place to put additional instructions.

    If let the LLM know that the fields are all optional, it’ll instead return None for the missing fields:

    -
    +
    class ArticleSpec(BaseModel):
         """Information about an article written in markdown"""
     
    @@ -722,12 +731,12 @@ 

    Data frames

    Token usage

    Below is a summary of the tokens used to create the output in this example.

    -
    +
    from chatlas import token_usage
     token_usage()
    -
    [{'name': 'OpenAI', 'input': 6081, 'output': 615},
    - {'name': 'Anthropic', 'input': 463, 'output': 137}]
    +
    [{'name': 'OpenAI', 'input': 6081, 'output': 642},
    + {'name': 'Anthropic', 'input': 463, 'output': 139}]
    @@ -1156,7 +1165,7 @@

    Token usage

    });
    -
    -