diff --git a/.github/workflows/build-cookbooks.yml b/.github/workflows/build-cookbooks.yml
new file mode 100644
index 000000000..6f7382a3f
--- /dev/null
+++ b/.github/workflows/build-cookbooks.yml
@@ -0,0 +1,72 @@
+name: generate-mdx-files
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths:
+ - 'fern/pages/cookbooks/**/*.mdx'
+ - 'scripts/build-cookbooks/**/*'
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.head_ref }}
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install Poetry
+ shell: bash
+ run: |
+ pipx install poetry
+
+
+ - name: Install Project Dependencies with Poetry
+ shell: bash
+ run: |
+ poetry install
+
+ # - name: Run mypy
+ # id: check_mypy
+ # run: |
+ # if grep -q 'mypy' pyproject.toml; then
+ # echo "mypy is specified in pyproject.toml, running..."
+ # poetry run mypy .
+ # echo "mypy_run=true" >> $GITHUB_ENV
+ # else
+ # echo "mypy is not specified in pyproject.toml, exiting."
+ # echo "mypy_run=false" >> $GITHUB_ENV
+ # fi
+ # shell: bash
+
+ - name: Build Cookbooks MDX Files
+ #if: env.mypy_run == 'true'
+ run: poetry run python scripts/build-cookbooks/build.py
+ shell: bash
+
+ - name: Check for Changes
+ id: check_changes
+ shell: bash
+ run: |
+ git add fern/pages/cookbooks* # Ensure this path is correct
+ git diff --cached --exit-code || echo "::set-output name=changes_detected::true"
+ continue-on-error: true
+
+ - name: Commit and Push Changes
+ if: steps.check_changes.outputs.changes_detected == 'true'
+ shell: bash
+ run: |
+ git config user.name "GitHub Actions"
+ git config user.email "actions@github.com"
+ git commit -m "Update cookbooks"
+ git push origin HEAD:refs/heads/${{ github.head_ref }}
diff --git a/fern/pages/cookbooks/agent-api-calls.mdx b/fern/pages/cookbooks/agent-api-calls.mdx
index d8ebdc458..19a12d431 100644
--- a/fern/pages/cookbooks/agent-api-calls.mdx
+++ b/fern/pages/cookbooks/agent-api-calls.mdx
@@ -1,9 +1,9 @@
---
-title: Building an LLM Agent with the Cohere API
+title: Agent API Calls
slug: /page/agent-api-calls
description: "This page how to use Cohere's API to build an LLM-based agent."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, agents, LLMs"
---
@@ -14,44 +14,63 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Marco Del Tredici",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg"
+ }
]}
/>
-
-## Motivation
+
+
+
+
+## Motivation
Agents can play a crucial role in different enterprise scenarios. One such example is creating a request to fetch results from an existing enterprise API with specific requirements. For example, given a user query:
-`Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS'`
+```Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS'```
The expected API request is:
-`[{"uuid":["7410e652-639d-402e-984e-8fd7025f0aac","8bb21b93-2ddf-4a63-af63-ddb6b1be49a1"],"page":0,"size":10}, {"objref":["GLPNT0005GUJOGGE","GLSBR000BGASOBRE"],"page":0,"size":10},{"nmgs":["0000234GLCHL0200ARTINDIUS"],"page":0,"size":10}]`
+```[{"uuid":["7410e652-639d-402e-984e-8fd7025f0aac","8bb21b93-2ddf-4a63-af63-ddb6b1be49a1"],"page":0,"size":10}, {"objref":["GLPNT0005GUJOGGE","GLSBR000BGASOBRE"],"page":0,"size":10},{"nmgs":["0000234GLCHL0200ARTINDIUS"],"page":0,"size":10}]```
-This kind of task poses a major challenge, namely, the model must be very precise at identifying the codes in the query, based on their alphanumeric patterns, and matching these codes with the right parameter - for example, the code `GLSBR000BGASOBRE` needs to map to
-`objref`. The task is even more challenging when multiple APIs are available, and the model has to deal with a plethora of parameters.
+This kind of task poses a major challenge, namely, the model must be very precise at identifying the codes in the query, based on their alphanumeric patterns, and matching these codes with the right parameter - for example, the code ```GLSBR000BGASOBRE``` needs to map to
+```objref```. The task is even more challenging when multiple APIs are available, and the model has to deal with a plethora of parameters.
## Solution
-
In this notebook, we propose a simple but effective solution to the challenge defined above: We create a [Langchain ReAct Agent](https://github.com/langchain-ai/langchain-cohere/blob/main/libs/cohere/langchain_cohere/cohere_agent.py) that has access to a deterministic tool that extracts the alphanumeric patterns in the query, and returns a dictionary in which the keys are the parameters, and the values the extracted patterns. The output of the tool is then used to generate the final request.
-Using such a tool is just one of the possibilities that the Agent has to generate the query. As we will see below, when a more semantic understanding of the query is required, we can ignore the tool and leverage the linguistic capabilities of the LLM powering the Agent to generate the final output.
+Using such a tool is just one of the possibilities that the Agent has to generate the query: As we will see below, when a more semantic understanding of the query is required, we can ignore the tool and leverage the linguistic capabilities of the LLM powering the Agent to generate the final output.
+
+With this approach, we bring together the best of two worlds: on the one hand, the ability of LLMs to use tool and generate outputs, on the other one, the reliability and efficiency of deterministic functions.
-With this approach, we bring together the best of two worlds: the ability of LLMs to use tools and generate outputs and the reliability and efficiency of deterministic functions.
+## Table of Contents
-# Step 1: Setup [#sec_step1]
+- [Step 1: Setup](#sec_step1)
+- [Step 2: Define the Tool and the Agent](#sec_step2)
+- [Step 3: Run the Agent](#sec_step3)
+- [Conclusions](#sec_conclusion)
+
-```python PYTHON
+
+# Step 1: Setup
+
+
+```python
+####################################################################################################
+#
# Uncomment if you need to install the following packages
+#
+####################################################################################################
+
# !pip install cohere
# !pip install python-dotenv
# !pip install pandas
+
```
-```python PYTHON
+
+```python
import os
import json
import re
@@ -64,20 +83,22 @@ from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.tools import tool
```
-```python PYTHON
+
+```python
# load the cohere api key
os.environ["COHERE_API_KEY"] = getpass.getpass()
```
-# Step 2: Define the Tool and the Agent [#sec_step2]
+
+# Step 2: Define the Tool and the Agent
+Here we create a tool which implements the deterministic function to extract alphanumeric strings from the user's query and match them to the right parameter.
-Here we create a tool which implements the deterministic function to extract alphanumeric strings
-from the user's query and match them to the right parameter.
-```python PYTHON
+```python
@tool
def regex_extractor(user_query: str) -> dict:
"""Function which, given the query from the user, returns a dictionary parameter:value."""
+
uuid = re.findall("\s([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})", user_query)
nmgs = re.findall("(0000[A-Z0-9]{21})", user_query)
objref = re.findall("\s([A-Z]{5,9}\d{3,4}[A-Z]{3,8})", user_query)
@@ -89,48 +110,54 @@ def regex_extractor(user_query: str) -> dict:
d_filtered = {k: v for k, v in d.items() if v != []}
return d_filtered
+
class extract_code_v1productssearch(BaseModel):
user_query: str = Field(
description="This is the full input query as received from the user. Do not truncate or modify the query in any way."
)
+
regex_extractor.name = "regex_extractor"
regex_extractor.args_schema = extract_code_v1productssearch
tools=[regex_extractor]
```
-```python PYTHON
+
+```python
# Let's define the preamble for the Agent.
# The preamble includes info about:
# - the tool the Agent has access to
# - the cases in which the Agent has to produce an output without using the tool
# - some examples to clarify the task
preamble = """You are an assistant that given a user's query about, generates a request an API.
-You can use the tool named "regex_extractor".
-Pass to the "regex_extractor" tool the entire text of the the input query.
-The tool returns a dictionary, in which keys are the name of the codes, and values a list of extracted codes.
-Create a JSON for each of the key-value pairs in the dictionary.
+ You can use the tool named "regex_extractor".
+ Pass to the "regex_extractor" tool the entire text of the the input query.
+ The tool returns a dictionary, in which keys are the name of the codes, and values a list of extracted codes.
+ Create a JSON for each of the key-value pairs in the dictionary.
-Return a list of JSONs. Make sure each JSON is properly defined. Do not return any other explanation or comment.
-You MUST generate a perfect JSON object: make sure that each string in the lists is included between quotes.
+ Return a list of JSONs. Make sure each JSON is properly defined. Do not return any other explanation or comment.
+ You MUST generate a perfect JSON object: make sure that each string in the lists is included between quotes.
-If the request mentions one of the tags listed below, or a related word, create a dictionary in which the key is "taxonomies" and the value the list of capitalized tags.
-Tags list: cars, trucks, clothes, sport
+ If the request mentions one of the tags listed below, or a related word, create a dictionary in which the key is "taxonomies" and the value the list of capitalized tags.
+ Tags list: cars, trucks, clothes, sport
-Find a list of examples here:
-User question | parameter for the tool | what you should understand
-Look products GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE | Look products GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE | [{"objref":["GLCMS004AGTCAMIS","GLCHL000CGUCHALE"]},{"nmgs":["0000234GLCMS0100ANORAKCAA"]}]
-Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS | Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS | [{"uuid":["7410e652-639d-402e-984e-8fd7025f0aac","8bb21b93-2ddf-4a63-af63-ddb6b1be49a1"]}, {"objref":["GLPNT0005GUJOGGE","GLSBR000BGASOBRE"]},{"nmgs":["0000234GLCHL0200ARTINDIUS"]}]
-Look for items of cars and trucks | Look for items of pants and t-shirts | [{'taxonomies': ['CARS', 'TRUCKS']}]
-Search products sport | Search products dress and jumpsuit | [{'taxonomies': ['SPORT']}]
-"""
+ Find a list of examples here:
+ User question | parameter for the tool | what you should understand
+ Look products GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE | Look products GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE | [{"objref":["GLCMS004AGTCAMIS","GLCHL000CGUCHALE"]},{"nmgs":["0000234GLCMS0100ANORAKCAA"]}]
+ Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS | Retrieve id 7410e652-639d-402e-984e-8fd7025f0aac 8bb21b93-2ddf-4a63-af63-ddb6b1be49a1, ref GLPNT0005GUJOGGE GLSBR000BGASOBRE, nmg 0000234GLCHL0200ARTINDIUS | [{"uuid":["7410e652-639d-402e-984e-8fd7025f0aac","8bb21b93-2ddf-4a63-af63-ddb6b1be49a1"]}, {"objref":["GLPNT0005GUJOGGE","GLSBR000BGASOBRE"]},{"nmgs":["0000234GLCHL0200ARTINDIUS"]}]
+ Look for items of cars and trucks | Look for items of pants and t-shirts | [{'taxonomies': ['CARS', 'TRUCKS']}]
+ Search products sport | Search products dress and jumpsuit | [{'taxonomies': ['SPORT']}]
+ """
```
-```python PYTHON
+
+```python
# Define the prompt
prompt = ChatPromptTemplate.from_template("{input}")
+
# Define the agent
llm = ChatCohere(model="command-r-plus", temperature=0)
+
# instantiate agent and agent executor
agent = create_cohere_react_agent(
llm=llm,
@@ -144,7 +171,8 @@ agent_executor = AgentExecutor(agent=agent,
)
```
-```python PYTHON
+
+```python
# finally, let's write a function to convert the Agents output to a json
def convert_to_json(string: str) -> json:
return json.loads(
@@ -153,13 +181,15 @@ def convert_to_json(string: str) -> json:
.replace("`", "")
.replace("`", "")
)
-```
-# Step 3: Run the Agent [#sec_step3]
+```
+
+# Step 3: Run the Agent
Let's now test the Agent we just defined!
-```python PYTHON
+
+```python
query_1 = "Look for urn:75f2b737-06dd-4399-9206-a6c11b65138e, GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE"
response_1 = agent_executor.invoke(
{
@@ -169,52 +199,58 @@ response_1 = agent_executor.invoke(
)
```
-````txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use the regex_extractor tool to extract the codes from the user query.
-{'tool_name': 'regex_extractor', 'parameters': {'user_query': 'Look for urn:75f2b737-06dd-4399-9206-a6c11b65138e, GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE'}}
-[0m[36;1m[1;3m{'nmgs': ['0000234GLCMS0100ANORAKCAA'], 'objref': ['GLCMS004AGTCAMIS', 'GLCHL000CGUCHALE'], 'urn': ['urn:75f2b737-06dd-4399-9206-a6c11b65138e']}[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: ```json JSON
-[
- {
- "urn": ["urn:75f2b737-06dd-4399-9206-a6c11b65138e"],
- "objref": ["GLCMS004AGTCAMIS", "GLCHL000CGUCHALE"],
- "nmgs": ["0000234GLCMS0100ANORAKCAA"]
- }
-]
-```
-Grounded answer: ```json JSON
- [
- {
- "urn": ["urn:75f2b737-06dd-4399-9206-a6c11b65138e"],
- "objref": ["GLCMS004AGTCAMIS", "GLCHL000CGUCHALE"],
- "nmgs": ["0000234GLCMS0100ANORAKCAA"]
- }
-]
-```[0m
-
-[1m> Finished chain.[0m
-````
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use the regex_extractor tool to extract the codes from the user query.
+ {'tool_name': 'regex_extractor', 'parameters': {'user_query': 'Look for urn:75f2b737-06dd-4399-9206-a6c11b65138e, GLCMS004AGTCAMIS; 0000234GLCMS0100ANORAKCAA, GLCHL000CGUCHALE'}}
+ [0m[36;1m[1;3m{'nmgs': ['0000234GLCMS0100ANORAKCAA'], 'objref': ['GLCMS004AGTCAMIS', 'GLCHL000CGUCHALE'], 'urn': ['urn:75f2b737-06dd-4399-9206-a6c11b65138e']}[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: ```json
+ [
+ {
+ "urn": ["urn:75f2b737-06dd-4399-9206-a6c11b65138e"],
+ "objref": ["GLCMS004AGTCAMIS", "GLCHL000CGUCHALE"],
+ "nmgs": ["0000234GLCMS0100ANORAKCAA"]
+ }
+ ]
+ ```
+ Grounded answer: ```json
+ [
+ {
+ "urn": ["urn:75f2b737-06dd-4399-9206-a6c11b65138e"],
+ "objref": ["GLCMS004AGTCAMIS", "GLCHL000CGUCHALE"],
+ "nmgs": ["0000234GLCMS0100ANORAKCAA"]
+ }
+ ]
+ ```[0m
+
+ [1m> Finished chain.[0m
+
In the reasoning chain above, we can see that the Agent uses the tool we provided it to extract the strings in the query.
The output of the tool is then used to generate the request.
-```python PYTHON
+
+```python
# let's have a look at the final output
convert_to_json(response_1['output'])
```
-```python title="Output"
-[{'urn': ['urn:75f2b737-06dd-4399-9206-a6c11b65138e'],
- 'objref': ['GLCMS004AGTCAMIS', 'GLCHL000CGUCHALE'],
- 'nmgs': ['0000234GLCMS0100ANORAKCAA']}]
-```
+
+
+
+ [{'urn': ['urn:75f2b737-06dd-4399-9206-a6c11b65138e'],
+ 'objref': ['GLCMS004AGTCAMIS', 'GLCHL000CGUCHALE'],
+ 'nmgs': ['0000234GLCMS0100ANORAKCAA']}]
+
+
As mentioned above, the Agent can use the tool when specific alphanumeric patterns have to be extracted from the query; however, it can also generate the output based on its semantic understanding of the query. For example:
-```python PYTHON
+
+```python
query_2 = "I need tennis products"
response_2 = agent_executor.invoke(
@@ -225,48 +261,54 @@ response_2 = agent_executor.invoke(
)
```
-````txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use the regex_extractor tool to extract the relevant information from the user request.
-{'tool_name': 'regex_extractor', 'parameters': {'user_query': 'I need tennis products'}}
-[0m[36;1m[1;3m{}[0m[32;1m[1;3mRelevant Documents: None
-Cited Documents: None
-Answer: ```json JSON
-[
- {
- "taxonomies": [
- "SPORT"
- ]
- }
-]
-```
-Grounded answer: ```json JSON
- [
- {
- "taxonomies": [
- "SPORT"
- ]
- }
-]
-```[0m
-
-[1m> Finished chain.[0m
-````
-
-The Agent runs the tool to check if any target string was in the query, then it generated the request body based on its understanding.
-
-```python PYTHON
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use the regex_extractor tool to extract the relevant information from the user request.
+ {'tool_name': 'regex_extractor', 'parameters': {'user_query': 'I need tennis products'}}
+ [0m[36;1m[1;3m{}[0m[32;1m[1;3mRelevant Documents: None
+ Cited Documents: None
+ Answer: ```json
+ [
+ {
+ "taxonomies": [
+ "SPORT"
+ ]
+ }
+ ]
+ ```
+ Grounded answer: ```json
+ [
+ {
+ "taxonomies": [
+ "SPORT"
+ ]
+ }
+ ]
+ ```[0m
+
+ [1m> Finished chain.[0m
+
+
+The Agent run the tool to check if any target string was in the query, then it generated the request body based on its understanding.
+
+
+```python
convert_to_json(response_2['output'])
```
-```python title="Output"
-[{'taxonomies': ['SPORT']}]
-```
+
+
+
+ [{'taxonomies': ['SPORT']}]
+
+
Finally, the two paths to generation - deterministic and semantic - can be applied in parallel by the Agent, as shown below:
-```python PYTHON
+
+```python
query_3 = "Look for GLBRL0000GACHALE, nmg 0000234GLCZD0000GUREDTOAA and car products"
response_3 = agent_executor.invoke(
@@ -277,48 +319,59 @@ response_3 = agent_executor.invoke(
)
```
-````txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use the regex_extractor tool to extract the codes from the user query. Then, I will create a JSON for each of the key-value pairs in the dictionary.
-{'tool_name': 'regex_extractor', 'parameters': {'user_query': 'Look for GLBRL0000GACHALE, nmg 0000234GLCZD0000GUREDTOAA and car products'}}
-[0m[36;1m[1;3m{'nmgs': ['0000234GLCZD0000GUREDTOAA'], 'objref': ['GLBRL0000GACHALE']}[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: ```json JSON
-[
- {
- "objref": ["GLBRL0000GACHALE"],
- "nmgs": ["0000234GLCZD0000GUREDTOAA"]
- },
- {
- "taxonomies": ["CARS"]
- }
-]
-```
-Grounded answer: ```json JSON
- [
- {
- "objref": ["GLBRL0000GACHALE"],
- "nmgs": ["0000234GLCZD0000GUREDTOAA"]
- },
- {
- "taxonomies": ["CARS"]
- }
-]
-```[0m
-
-[1m> Finished chain.[0m
-````
-
-```python PYTHON
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use the regex_extractor tool to extract the codes from the user query. Then, I will create a JSON for each of the key-value pairs in the dictionary.
+ {'tool_name': 'regex_extractor', 'parameters': {'user_query': 'Look for GLBRL0000GACHALE, nmg 0000234GLCZD0000GUREDTOAA and car products'}}
+ [0m[36;1m[1;3m{'nmgs': ['0000234GLCZD0000GUREDTOAA'], 'objref': ['GLBRL0000GACHALE']}[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: ```json
+ [
+ {
+ "objref": ["GLBRL0000GACHALE"],
+ "nmgs": ["0000234GLCZD0000GUREDTOAA"]
+ },
+ {
+ "taxonomies": ["CARS"]
+ }
+ ]
+ ```
+ Grounded answer: ```json
+ [
+ {
+ "objref": ["GLBRL0000GACHALE"],
+ "nmgs": ["0000234GLCZD0000GUREDTOAA"]
+ },
+ {
+ "taxonomies": ["CARS"]
+ }
+ ]
+ ```[0m
+
+ [1m> Finished chain.[0m
+
+
+
+```python
convert_to_json(response_3['output'])
```
-```python title="Output"
-[{'objref': ['GLBRL0000GACHALE'], 'nmgs': ['0000234GLCZD0000GUREDTOAA']},
- {'taxonomies': ['CARS']}]
-```
-# Conclusions [#sec_conclusion]
+
+
+ [{'objref': ['GLBRL0000GACHALE'], 'nmgs': ['0000234GLCZD0000GUREDTOAA']},
+ {'taxonomies': ['CARS']}]
+
+
+
+
+# Conclusions
In this notebook we showed how Agents can be used to solve a real-world use case, in which the goal is to create API requests based on the user's query. We did it by providing the Agent with a deterministic tool to extract relevant alphanumeric strings in the query, and matching them to the right parameter name. In parallel, the Agent can leverage the semantic understanding of the query provided by the LLM powering it.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/agent-short-term-memory.mdx b/fern/pages/cookbooks/agent-short-term-memory.mdx
index b04f59f88..8a803434d 100644
--- a/fern/pages/cookbooks/agent-short-term-memory.mdx
+++ b/fern/pages/cookbooks/agent-short-term-memory.mdx
@@ -3,7 +3,7 @@ title: Short-Term Memory Handling for Agents
slug: /page/agent-short-term-memory
description: "This page describes how to manage short-term memory in an agent built with Cohere models."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, agents, short-term memory"
---
@@ -14,40 +14,58 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Marco Del Tredici",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg"
+ }
]}
/>
-
-## Motivation
+
+
+
-Users frequently engage in long conversations with LLMs with the expectation that the LLM fully recalls what was said in the previous turns.
+## Motivation
+Users frequently engage in long conversations with LLMs with the expectation that the LLM fully recalls what was said in the previous turns.
The way we make LLMs aware of previous information is by simply providing them the full conversation history, i.e., the concatenation of previous input queries and generations.
As Agents become more and more used, we face the issue to make Agents fully aware of the info from previous turns.
-The current approach is to pass the Agent the generations of the previous turns (see https://python.langchain.com/docs/modules/agents/how_to/custom_agent/). However, as we show below, while this is a good approach for LLMs it is not for Agents. Given the same input, LLMs _only_ produce the final generation; conversely, Agents _first_ produce a reasoning chain (intermediate steps), _then_ produce the final outcome. Hence, if we only retain the final generation we lose some crucial info: the reasoning chain.
+The current approach is to pass the Agent the generations of the previous turns (see https://python.langchain.com/docs/modules/agents/how_to/custom_agent/), i.e., to do the same thing we do with LLMs. However, as we show below, while this is a good approach for LLMs, it is not for Agents. The reason is that, given the same input, LLMs *only* produce the final generation; conversely, Agents *first* produce a reasoning chain (intermediate steps), *then* produce the final outcome. Hence, if we only retain the final generation, we are loosing some crucial info: the reasoning chain.
-A straightforward solution to this issue would be to append to the conversation history from both the reasoning chain and the generations. This is problematic due to the fact that reasoning chains can be very long, especially when the model makes mistakes and corrects itself. Using the full reasoning chains would (i) introduce a lot of noise; (ii) quickly fill the whole input window of the model.
+A straightforward solution to this issue would be to append to the conversation history from both the reasoning chain and the generations. This is problematic due to the fact that reasoning chains can be very long, especially when the model makes mistakes, and corrects itself. Using the full reasoning chains would (i) introduce a lot of noise; (ii) quickly fill the whole input window of the model.
## Objective
-In this notebook we introduce a simple approach to address the issue described above. We propose to use _augmented memory objects_, which we define as compact and interpretable pieces of information based on the reasoning chain and the generation.
+In this notebook we introduce a simple approach to address the issue described above. We propose to use *augmented memory objects*, which we define as compact and interpretable pieces of information based on the reasoning chain and the generation.
Below, we show that, with augmented memory objects, the Agent is more aware of the information that emerged in the conversation, and, in turn, this makes the Agent behaviour more robust and effective.
-# Step 1: Setup the Prompt and the Agent [#sec_step1]
+## Table of Contents
+
+- [Step 1: Setup the Prompt and the Agent](#sec_step1)
+- [Step 2: Conversation without memory](#sec_step2)
+- [Step 3: Conversation with Memory using AI Messages](#sec_step3)
+- [Step 4: Conversation with Memory using AI Messages and Human Messages](#sec_step4)
+- [Step 5: Conversation with Memory using AI Messages and Human Messages](#sec_step5)
+
+
+# Step 1: Setup the Prompt and the Agent
-```python PYTHON
+
+```python
+####################################################################################################
+#
# Uncomment if you need to install the following packages
+#
+####################################################################################################
+
# !pip install cohere
# !pip install python-dotenv
# !pip install pandas
```
-```python PYTHON
+
+```python
import os
import pandas as pd
import getpass
@@ -63,22 +81,26 @@ from langchain_core.messages.system import SystemMessage
from langchain_core.messages.human import HumanMessage
```
-```python PYTHON
+
+```python
# load the cohere api key
os.environ["COHERE_API_KEY"] = getpass.getpass()
```
-```python PYTHON
+
+```python
# Load the data
revenue_table = pd.read_csv('revenue_table.csv')
```
-```python PYTHON
+
+```python
# Define the prompt
prompt = ChatPromptTemplate.from_template("{input}")
```
-```python PYTHON
+
+```python
# Define the tools
python_repl = PythonREPL()
python_tool = Tool(
@@ -95,7 +117,8 @@ python_tool.args_schema = ToolInput
tools=[python_tool]
```
-```python PYTHON
+
+```python
# Define the agent
llm = ChatCohere(model="command-r", temperature=0)
@@ -112,9 +135,12 @@ agent_executor = AgentExecutor(agent=agent,
)
```
-# Step 2: Conversation without memory [#sec_step2]
+
+# Step 2: Conversation without memory
+
-```python PYTHON
+
+```python
# let's start the conversation with a question about the csv we have loaded
q1 = "read revenue_table.csv and show me the column names"
a1=agent_executor.invoke({
@@ -122,29 +148,31 @@ a1=agent_executor.invoke({
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use python to read the CSV file and extract the column names.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\ndf = pd.read_csv('revenue_table.csv')\n\nprint(df.columns)"}}
-[0m[36;1m[1;3mIndex(['Unnamed: 0', 'time', 'revenue', 'loss'], dtype='object')
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The column names in the CSV file are:
-- Unnamed: 0
-- time
-- revenue
-- loss
-Grounded answer: The column names in the CSV file are:
-- Unnamed: 0
-- time
-- revenue
-- loss[0m
-
-[1m> Finished chain.[0m
-```
-
-```python PYTHON
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use python to read the CSV file and extract the column names.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\ndf = pd.read_csv('revenue_table.csv')\n\nprint(df.columns)"}}
+ [0m[36;1m[1;3mIndex(['Unnamed: 0', 'time', 'revenue', 'loss'], dtype='object')
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The column names in the CSV file are:
+ - Unnamed: 0
+ - time
+ - revenue
+ - loss
+ Grounded answer: The column names in the CSV file are:
+ - Unnamed: 0
+ - time
+ - revenue
+ - loss[0m
+
+ [1m> Finished chain.[0m
+
+
+
+```python
# nice! now let's ask a follow-up question
q2 = "plot revenue numbers"
a2_no_mem = agent_executor.invoke({
@@ -152,34 +180,35 @@ a2_no_mem = agent_executor.invoke({
})
```
-````txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3mPlan: I will ask the user for clarification on what data they would like to visualise.
-Action: ```json JSON
-[
- {
- "tool_name": "directly_answer",
- "parameters": {}
- }
-]
-```
-
-Relevant Documents: None
-Cited Documents: None
-Answer: Hello, could you please clarify what data you would like to see plotted?
-Grounded answer: Hello, could you please clarify what data you would like to see plotted?[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3mPlan: I will ask the user for clarification on what data they would like to visualise.
+ Action: ```json
+ [
+ {
+ "tool_name": "directly_answer",
+ "parameters": {}
+ }
+ ]
+ ```
+ Relevant Documents: None
+ Cited Documents: None
+ Answer: Hello, could you please clarify what data you would like to see plotted?
+ Grounded answer: Hello, could you please clarify what data you would like to see plotted?[0m
+
+ [1m> Finished chain.[0m
-[1m> Finished chain.[0m
-
-````
Without memory, the model cannot answer follow up questions because it misses the necessary previous context
-# Step 3: Conversation with Memory using AI Messages [#sec_step3]
+
+# Step 3. Conversation with Memory using AI Messages
Here we will populate the chat history only with the generations from the model. This is the current approach used, e.g., here: https://python.langchain.com/docs/modules/agents/how_to/custom_agent/
-```python PYTHON
+
+```python
# let's answer the followup question above with the new setup
a2_mem_ai = agent_executor.invoke({
"input": q2,
@@ -187,31 +216,35 @@ a2_mem_ai = agent_executor.invoke({
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will copy and paste the code from the previous conversation and add code to plot the revenue numbers.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('data/sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
-[0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3m
-The code is throwing an error because the file doesn't exist in the specified location. I will amend the file path and re-run the code.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
-[0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3m
-The file path is still incorrect. I will amend it and re-run the code.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('../data/sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
-[0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3mReflection: The file path is still incorrect. I will ask the user to provide the correct file path.
-Relevant Documents: 0,1,2
-Cited Documents: 0,1,2
-Answer: The file path provided is incorrect. Please provide the correct file path so that I can plot the revenue numbers. I have tried '../data/sample.csv' but this also doesn't work.
-Grounded answer: The file path provided is incorrect. Please provide the correct file path so that I can plot the revenue numbers. I have tried '../data/sample.csv' but this also doesn't work.[0m
-
-[1m> Finished chain.[0m
-```
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will copy and paste the code from the previous conversation and add code to plot the revenue numbers.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('data/sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
+ [0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3m
+ The code is throwing an error because the file doesn't exist in the specified location. I will amend the file path and re-run the code.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
+ [0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3m
+ The file path is still incorrect. I will amend it and re-run the code.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('../data/sample.csv')\n\n# Plot revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
+ [0m[36;1m[1;3mFileNotFoundError(2, 'No such file or directory')[0m[32;1m[1;3mReflection: The file path is still incorrect. I will ask the user to provide the correct file path.
+ Relevant Documents: 0,1,2
+ Cited Documents: 0,1,2
+ Answer: The file path provided is incorrect. Please provide the correct file path so that I can plot the revenue numbers. I have tried '../data/sample.csv' but this also doesn't work.
+ Grounded answer: The file path provided is incorrect. Please provide the correct file path so that I can plot the revenue numbers. I have tried '../data/sample.csv' but this also doesn't work.[0m
+
+ [1m> Finished chain.[0m
+
+
+Also in this case, the model cannot manage the follow up question. The reason is that the AI message tells is only part of the necessary context: we need more info from previous turns.
-Also in this case, the model cannot manage the follow up question. The reason is that the AI message only tells part of the necessary context: we need more info from previous turns.
-# Step 4: Conversation with Memory using AI Messages and Human Messages [#sec_step4]
+
+# Step 4: Conversation with Memory using AI Messages and Human Messages
-```python PYTHON
+
+```python
a2_mem_ai_hum = agent_executor.invoke({
"input": q2,
"chat_history": [HumanMessage(content=q1),
@@ -219,29 +252,32 @@ a2_mem_ai_hum = agent_executor.invoke({
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will copy and paste the code from the previous conversation into this one, and then use it to plot the revenue numbers.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
-[0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: Here's a plot of the revenue numbers:
-
-Grounded answer: Here's a plot of the revenue numbers:
-! [Revenue plot]("revenue_plot.png")[0m
-
-[1m> Finished chain.[0m
-```
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will copy and paste the code from the previous conversation into this one, and then use it to plot the revenue numbers.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}}
+ [0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: Here's a plot of the revenue numbers:
+
+ Grounded answer: Here's a plot of the revenue numbers:
+ ! [Revenue plot]("revenue_plot.png")[0m
+
+ [1m> Finished chain.[0m
-
-It works! Let's go on with the conversation.
-```python PYTHON
+
+
+
+
+
+It works! let's go on with the conversation.
+
+
+```python
q3 = "set the min of y axis to zero and the max to 1000"
a3_mem_ai_hum = agent_executor.invoke({
"input": q3,
@@ -252,37 +288,42 @@ a3_mem_ai_hum = agent_executor.invoke({
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will copy and paste the previous code and make the changes requested by the user. Then I will execute the code to plot the graph with the changes applied.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv("modified_revenue_table.csv")\n\n# Plot revenue against time\nplt.plot(df["time"], df["revenue"], marker="o")\n\n# Set minimum and maximum values for y-axis\nplt.ylim(0, 1000)\n\nplt.savefig("revenue_plot.png")'}}
-[0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: Here's the plot with the requested changes:
-
-Grounded answer: Here's the plot with the requested changes:
-! [Revenue plot]("revenue_plot.png")[0m
-
-[1m> Finished chain.[0m
-```
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will copy and paste the previous code and make the changes requested by the user. Then I will execute the code to plot the graph with the changes applied.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv("modified_revenue_table.csv")\n\n# Plot revenue against time\nplt.plot(df["time"], df["revenue"], marker="o")\n\n# Set minimum and maximum values for y-axis\nplt.ylim(0, 1000)\n\nplt.savefig("revenue_plot.png")'}}
+ [0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: Here's the plot with the requested changes:
+
+ Grounded answer: Here's the plot with the requested changes:
+ ! [Revenue plot]("revenue_plot.png")[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+
-
The model does what we asked, but it decides to introduce the marker="o" in the plotting function. While in this case the modification of the code does not affect the quality of the output, this is still an undesidered behaviour, since the model is introducing a modification that was not required.
-To address this problem, we can further enrich the chat history by adding information from the reasoning chain.
+To address this problem, we can further enrich the chat history, by adding information from the reasoning chain
+
+
+
+# Step 5: Conversation with Memory using AI Messages, Human Messages and the Reasoning Chain
-# Step 5: Conversation with Memory using AI Messages, Human Messages and the Reasoning Chain [#sec_step5]
+To enrich the chat history, we will include in it also the resoning chains produced by the model. Such chains can be very long, especially in those cases in which errors are made, and the agent needs several attempts to get to the final output. Hence, by concatenating all the reasoning chains, we might have two issues: (i) noisy information; (ii) we would quickly hit max input length.
-Reasoning chains can be very long, especially in the cases that contain errors and the agent needs several attempts to get to the final output. Hence, by concatenating all the reasoning chains, we might have two issues: (i) noisy information; (ii) we would quickly hit max input length.
+To avoid this issue, we need a way to extract the relevant info from the previous turns. Below, we propose a simple approach to info extraction. We format the extracted info in such a way to enhance human interpretability. We call the objects passed in the chat history *augmented memory objects*.
-To avoid this issue, we need a way to extract the relevant info from the previous turns. Below, we propose a simple approach to info extraction. We format the extracted info in such a way to enhance human interpretability. We call the objects passed in the chat history _augmented memory objects_.
-```python PYTHON
+```python
# function to create augmented memory objects
def create_augmented_mem_objs(output_previous_turn: dict) -> str:
"""Function to convert the output of a ReAct agent to a compact and interpretable representation"""
@@ -306,37 +347,39 @@ def create_augmented_mem_objs(output_previous_turn: dict) -> str:
return augmented_mem_obj
```
-```python PYTHON
+
+```python
augmented_mem_obj_a1 = create_augmented_mem_objs(a1)
augmented_mem_obj_a2 = create_augmented_mem_objs(a2_mem_ai_hum)
```
Below, an example of the augmented memory object generated by the model. You can see that the agent now has full visibility on what it did in the previous step.
-```python PYTHON
-print(augmented_mem_obj_a2)
-```
-
-```txt title="Output"
-This is the sequence of tools you used in the previous turn:
-
-START TOOL 0 NAME:
-python_interpreter
-END TOOL 0 NAME
-
-START INPUT 0 NAME:
-{'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}
-END INPUT 0 NAME
-
-This is the output you produced in the previous turn:
-START OUTPUT
-Here's a plot of the revenue numbers:
-! [Revenue plot]("revenue_plot.png")
-END OUTPUT
+```python
+print(augmented_mem_obj_a2)
```
-```python PYTHON
+ This is the sequence of tools you used in the previous turn:
+
+ START TOOL 0 NAME:
+ python_interpreter
+ END TOOL 0 NAME
+
+ START INPUT 0 NAME:
+ {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\nplt.savefig('revenue_plot.png')"}
+ END INPUT 0 NAME
+
+
+ This is the output you produced in the previous turn:
+ START OUTPUT
+ Here's a plot of the revenue numbers:
+ ! [Revenue plot]("revenue_plot.png")
+ END OUTPUT
+
+
+
+```python
a3_mem_ai_hum_amo = agent_executor.invoke({
"input": q3,
"chat_history": [SystemMessage(content=augmented_mem_obj_a1),
@@ -345,30 +388,37 @@ a3_mem_ai_hum_amo = agent_executor.invoke({
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will copy and paste the previous code, and modify the y axis limits as requested.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\n# Set y axis limits\nplt.ylim(0, 1000)\n\nplt.savefig('revenue_plot.png')"}}
-[0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: Here's the plot with the requested y axis limits:
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will copy and paste the previous code, and modify the y axis limits as requested.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\nimport matplotlib.pyplot as plt\n\ndata = pd.read_csv('modified_revenue_table.csv')\n\n# Plot the revenue numbers\nplt.plot(data['revenue'])\n\n# Set y axis limits\nplt.ylim(0, 1000)\n\nplt.savefig('revenue_plot.png')"}}
+ [0m[36;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: Here's the plot with the requested y axis limits:
+
+
+ Grounded answer: Here's the plot with the requested y axis limits:
+
+ ! [Revenue plot]("revenue_plot.png")[0m
+
+ [1m> Finished chain.[0m
-
-Grounded answer: Here's the plot with the requested y axis limits:
-! [Revenue plot]("revenue_plot.png")[0m
-[1m> Finished chain.[0m
-```
+
+
+
-
We can see that, now, the plot only includes the modification we asked for, and nothing else. This is possible because we are now providing the Agent with the code it previously generated, and the Agent re-uses that code, making only the necessary modifications. This is fundamentally different from what we observed before, when the Agent had to re-create from scratch the code.
In sum, by providing the Agent with the information about its previous Reasoning Chain, we make it more robust and able to generate consistent outputs.
In a future post, we will explore how to handle really long historical context using vector databases.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/agentic-multi-stage-rag.mdx b/fern/pages/cookbooks/agentic-multi-stage-rag.mdx
index 2d08a7a34..06c803044 100644
--- a/fern/pages/cookbooks/agentic-multi-stage-rag.mdx
+++ b/fern/pages/cookbooks/agentic-multi-stage-rag.mdx
@@ -3,7 +3,7 @@ title: Agentic Multi-Stage RAG with Cohere Tools API
slug: /page/agentic-multi-stage-rag
description: "This page describes how to build a powerful, multi-stage agent with the Cohere platform."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, agents, LLMs"
---
@@ -14,38 +14,46 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Jason Jung",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg"
+ }
]}
/>
-
-## Motivation
+
+
+
+## Motivation
-Retrieval augmented generation (RAG) has been a go-to use case that enterprises have been adopting with large language models (LLMs). Even though it works well in general, there are edge cases where this can fail. Most commonly, when the retrieved document mentions the query but actually refers to another document, the model will fail to generate the correct answer.
+Retrieval augmented generation (RAG) has been a go-to use case that enterprises have been adopting with large language models (LLMs). Even though it works well in general, there are edge cases where this can fail. Most commonly, when the retrieved document mentions the query but actually refers to another document, the model will fail to generate the correct answer.
+
+We propose an agentic RAG system that leverages tool use to continue to retrieve documents if correct ones were not retrieved at first try. This is ideal for use cases where accuracy is a top priority and latency is not. For example, lawyers trying to find the most accurate answer from their contracts are willing to wait a few more seconds to get the answer instead of getting wrong answers fast.
-We propose an agentic RAG system that leverages tool use to continue to retrieve documents if correct ones were not retrieved at first try. This is ideal for use cases where accuracy is a top priority and latency is not. For example, lawyers trying to find the most accurate answer from their contracts are willing to wait a few more seconds to get the answer instead of getting wrong answers fast.
## Objective
-This notebook, we will explore how we can build a simple agentic RAG using Cohere's native API. We have prepared a fake dataset to demonstrate the use case.
-We ask three questions that require different depths of retrieval. We will see how the model answers the question between simple and agentic RAG.
+This notebook, we will explore how we can build a simple agentic RAG using Cohere's native API. We have prepared a fake dataset to demonstrate the use case.
+We ask three questions that require different depths of retrieval. We will see how the model answers the question between simple and agentic RAG.
+
+
+## Disclaimer
-## Disclaimer
+One of the challenges in building a RAG system is that it has many moving pieces: vector database, type of embedding model, use of reranker, number of retrieved documents, chunking strategy, and more. These components can make debugging and evaluating RAG systems difficult. Since this notebook focuses on the concept of agentic RAG, it will simplify other parts of the RAG system. For example, we will only retrieve top 1 docuemnt to demonstrate what happens when retrieved document does not contain the answer needed.
-One of the challenges in building a RAG system is that it has many moving pieces: vector database, type of embedding model, use of reranker, number of retrieved documents, chunking strategy, and more. These components can make debugging and evaluating RAG systems difficult. Since this notebook focuses on the concept of agentic RAG, it will simplify other parts of the RAG system. For example, we will only retrieve top 1 document to demonstrate what happens when retrieved document does not contain the answer needed.
-## Result
+## Result
-| Type | Question | Simple Rag | Agentic Rag |
-| ---------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
-| Single-stage retrieval | Is there a state level law for wearing helmets? | There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use. | There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles. |
-| Multi-stage retrieval | I live in orting, do I need to wear a helmet with a bike? | In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws. | Yes, you do need to wear a helmet with a bike in Orting if you are under 17. |
+|Type | Question | Simple Rag | Agentic Rag |
+|---|--------------|---------|---------|
+|Single-stage retrieval| Is there a state level law for wearing helmets? | There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use. | There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles. |
+|Multi-stage retrieval|I live in orting, do I need to wear a helmet with a bike?|In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws.|Yes, you do need to wear a helmet with a bike in Orting if you are under 17.|
-As you will see more below, the multi-stage retrieval is achieved by adding a new function `reference_extractor()` that extracts other references in the documents and updating the instruction so the agent continues to retrieve more documents.
+As you will see more below, the multi-stage retrieval is achieved by adding a new function `reference_extractor()` that extracts other references in the documents and updating the instruction so the agent continues to retrieve more documents.
-```python PYTHON
+
+
+
+```python
import os
from pprint import pprint
@@ -54,28 +62,30 @@ import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
```
-```python PYTHON
+
+```python
# versions
print('cohere version:', cohere.__version__)
```
-```txt title="Output"
-cohere version: 5.5.1
-```
+ cohere version: 5.5.1
+
-## Setup
+## Setup
-```python PYTHON
+
+```python
COHERE_API_KEY = os.environ.get("CO_API_KEY")
COHERE_MODEL = 'command-r-plus'
co = cohere.Client(api_key=COHERE_API_KEY)
```
-## Data
+## Data
+
+We leveraged data from [Washington Department of Transportation](https://wsdot.wa.gov/travel/bicycling-walking/bicycling-washington/bicyclist-laws-safety) and modified to fit the need of this demo.
-We leveraged data from [Washington Department of Transportation](https://wsdot.wa.gov/travel/bicycling-walking/bicycling-washington/bicyclist-laws-safety) and modified to fit the need of this demo.
-```python PYTHON
+```python
documents = [
{
"title": "Bicycle law",
@@ -136,59 +146,79 @@ db["embeddings"] = embeddings.embeddings
```
-```python PYTHON
+
+```python
db
```
+
+
+
-
-
-
- |
- title |
- body |
- combined |
- embeddings |
-
-
-
-
- 0 |
- Bicycle law |
- \n Traffic Infractions and fees - For a... |
- Title: Bicycle law\nBody: \n Traffic In... |
- [-0.024673462, -0.034729004, 0.0418396, 0.0121... |
-
-
- 1 |
- Bicycle helmet requirement |
- Currently, there is no state law requiring hel... |
- Title: Bicycle helmet requirement\nBody: Curre... |
- [-0.019180298, -0.037384033, 0.0027389526, -0.... |
-
-
- 2 |
- Section 21a |
- helmet rules by location: These are city and c... |
- Title: Section 21a\nBody: helmet rules by loca... |
- [0.031097412, 0.0007619858, -0.023010254, -0.0... |
-
-
- 3 |
- Section 3b |
- Traffic infraction - A person operating a bicy... |
- Title: Section 3b\nBody: Traffic infraction - ... |
- [0.015602112, -0.016143799, 0.032958984, 0.000... |
-
-
-
+
+
+
+
+ |
+ title |
+ body |
+ combined |
+ embeddings |
+
+
+
+
+ 0 |
+ Bicycle law |
+ \n Traffic Infractions and fees - For a... |
+ Title: Bicycle law\nBody: \n Traffic In... |
+ [-0.024673462, -0.034729004, 0.0418396, 0.0121... |
+
+
+ 1 |
+ Bicycle helmet requirement |
+ Currently, there is no state law requiring hel... |
+ Title: Bicycle helmet requirement\nBody: Curre... |
+ [-0.019180298, -0.037384033, 0.0027389526, -0.... |
+
+
+ 2 |
+ Section 21a |
+ helmet rules by location: These are city and c... |
+ Title: Section 21a\nBody: helmet rules by loca... |
+ [0.031097412, 0.0007619858, -0.023010254, -0.0... |
+
+
+ 3 |
+ Section 3b |
+ Traffic infraction - A person operating a bicy... |
+ Title: Section 3b\nBody: Traffic infraction - ... |
+ [0.015602112, -0.016143799, 0.032958984, 0.000... |
+
+
+
-## Tools
-Following functions and tools will be used in the subsequent tasks.
-```python PYTHON
+## Tools
+
+Following functions and tools will be used in the subsequent tasks.
+
+
+```python
def retrieve_documents(query: str, n=1) -> dict:
"""
Function to retrieve documents a given query.
@@ -229,9 +259,11 @@ tools = [
```
-## RAG function
+## RAG function
+
-```python PYTHON
+
+```python
def simple_rag(query, db):
"""
Given user's query, retrieve top documents and generate response using documents parameter.
@@ -250,7 +282,8 @@ def simple_rag(query, db):
## Agentic RAG - cohere_agent()
-```python PYTHON
+
+```python
def cohere_agent(
message: str,
preamble: str,
@@ -324,34 +357,38 @@ def cohere_agent(
```
-## Question 1 - single-stage retrieval
+## Question 1 - single-stage retrieval
+
+Here we are asking a question that can be answered easily with single-stage retrieval. Both regular and agentic RAG should be able to answer this question easily. Below is the comparsion of the response.
+
+| Question | Simple Rag | Agentic Rag |
+|--------------|---------|---------|
+| Is there a state level law for wearing helmets? | There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use. | There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles. |
+
-Here we are asking a question that can be answered easily with single-stage retrieval. Both regular and agentic RAG should be able to answer this question easily. Below is the comparsion of the response.
-| Question | Simple Rag | Agentic Rag |
-| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
-| Is there a state level law for wearing helmets? | There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use. | There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles. |
-```python PYTHON
+```python
question1 = "Is there a state level law for wearing helmets?"
```
-### Simple RAG
+### Simple RAG
-```python PYTHON
+
+```python
output = simple_rag(question1, db)
print(output)
```
-```txt title="Output"
-top_matched_document 1 Title: Bicycle helmet requirement\nBody: Curre...
-Name: combined, dtype: object
-There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use.
-```
+ top_matched_document 1 Title: Bicycle helmet requirement\nBody: Curre...
+ Name: combined, dtype: object
+ There is currently no state law requiring the use of helmets when riding a bicycle. However, some cities and counties do require helmet use.
-### Agentic RAG
-```python PYTHON
+### Agentic RAG
+
+
+```python
preamble = """
You are an expert assistant that helps users answers question about legal documents and policies.
Use the provided documents to answer questions about an employee's specific situation.
@@ -360,49 +397,52 @@ Use the provided documents to answer questions about an employee's specific situ
output = cohere_agent(question1, preamble, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will search for 'state level law for wearing helmets' in the documents provided and write an answer based on what I find.
-
-running 1th step.
-= running tool retrieve_documents, with parameters:
-{'query': 'state level law for wearing helmets'}
-== tool results:
-{'top_matched_document': 1 Title: Bicycle helmet requirement\nBody: Curre...
-Name: combined, dtype: object}
-There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles.
-```
+
+ running 0th step.
+ I will search for 'state level law for wearing helmets' in the documents provided and write an answer based on what I find.
+
+ running 1th step.
+ = running tool retrieve_documents, with parameters:
+ {'query': 'state level law for wearing helmets'}
+ == tool results:
+ {'top_matched_document': 1 Title: Bicycle helmet requirement\nBody: Curre...
+ Name: combined, dtype: object}
+ There is currently no state law requiring helmet use. However, some cities and counties do require helmet use with bicycles.
-## Question 2 - double-stage retrieval
-The second question requires a double-stage retrieval because top matched document references another document. You will see below that the agentic RAG is unable to produce the correct answer initially. But when given proper tools and instructions, it finds the correct answer.
+## Question 2 - double-stage retrieval
-| Question | Simple Rag | Agentic Rag |
-| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
-| I live in orting, do I need to wear a helmet with a bike? | In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws. | Yes, you do need to wear a helmet with a bike in Orting if you are under 17. |
+The second question requires a double-stage retrieval because top matched document references another document. You will see below that the agentic RAG is unable to produce the correct answer initially. But when given proper tools and instructions, it finds the correct answer.
-```python PYTHON
+
+| Question | Simple Rag | Agentic Rag |
+|--------------|---------|---------|
+|I live in orting, do I need to wear a helmet with a bike?|In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws.|Yes, you do need to wear a helmet with a bike in Orting if you are under 17.|
+
+
+```python
question2 = "I live in orting, do I need to wear a helmet with a bike?"
```
-### Simple RAG
+### Simple RAG
+
-```python PYTHON
+```python
output = simple_rag(question2, db)
print(output)
```
-```txt title="Output"
-top_matched_document 1 Title: Bicycle helmet requirement\nBody: Curre...
-Name: combined, dtype: object
-In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws.
-```
+ top_matched_document 1 Title: Bicycle helmet requirement\nBody: Curre...
+ Name: combined, dtype: object
+ In the state of Washington, there is no law requiring you to wear a helmet when riding a bike. However, some cities and counties do require helmet use, so it is worth checking your local laws.
+
### Agentic RAG
Produces same quality answer as the simple rag.
-```python PYTHON
+
+```python
preamble = """
You are an expert assistant that helps users answers question about legal documents and policies.
Use the provided documents to answer questions about an employee's specific situation.
@@ -411,27 +451,27 @@ Use the provided documents to answer questions about an employee's specific situ
output = cohere_agent(question2, preamble, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will search for 'helmet with a bike' and then write an answer.
-
-running 1th step.
-= running tool retrieve_documents, with parameters:
-{'query': 'helmet with a bike'}
-== tool results:
-{'top_matched_document': 1 Title: Bicycle helmet requirement\nBody: Curre...
-Name: combined, dtype: object}
-There is no state law requiring helmet use, however, some cities and counties do require helmet use with bicycles. I cannot find any information about Orting specifically, but you should check with your local authority.
-```
+
+ running 0th step.
+ I will search for 'helmet with a bike' and then write an answer.
+
+ running 1th step.
+ = running tool retrieve_documents, with parameters:
+ {'query': 'helmet with a bike'}
+ == tool results:
+ {'top_matched_document': 1 Title: Bicycle helmet requirement\nBody: Curre...
+ Name: combined, dtype: object}
+ There is no state law requiring helmet use, however, some cities and counties do require helmet use with bicycles. I cannot find any information about Orting specifically, but you should check with your local authority.
+
-### Agentic RAG - New Tools
+### Agentic RAG - New Tools
-In order for the model to retrieve correct documents, we do two things:
+In order for the model to retrieve correct documents, we do two things:
+1. New reference_extractor() function is added. This function finds the references to other documents when given query and documents.
+2. We update the instruction that directs the agent to keep retrieving relevant documents.
-1. New reference_extractor() function is added. This function finds the references to other documents when given query and documents.
-2. We update the instruction that directs the agent to keep retrieving relevant documents.
-```python PYTHON
+```python
def reference_extractor(query: str, documents: list[str]) -> str:
"""
Given a query and document, find references to other documents.
@@ -495,13 +535,14 @@ tools = [
```
-```python PYTHON
+
+```python
preamble2 = """# Instruction
-You are an expert assistant that helps users answer questions about legal documents and policies.
+You are an expert assistant that helps users answers question about legal documents and policies.
Please follow these steps:
1. Using user's query, use `retrieve_documents` tool to retrieve the most relevant document from the database.
-2. If you see `other_references_to_query` in the tool result, search the mentioned referenced using `retrieve_documents()` tool to retrieve more documents.
+2. If you see `other_references_to_query` in the tool result, search the mentioned referenced using `retrieve_documents()` tool to retrieve more documents.
3. Keep trying until you find the answer.
4. Answer with yes or no as much as you can to answer the question directly.
"""
@@ -509,25 +550,25 @@ Please follow these steps:
output = cohere_agent(question2, preamble2, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will search for 'Orting' and 'bike helmet' to find the relevant information.
-
-running 1th step.
-= running tool retrieve_documents, with parameters:
-{'query': 'Orting bike helmet'}
-== tool results:
-{'other_references_to_query': 'Section 21a, Section 3b',
- 'top_matched_document': 0 Title: Bicycle law\nBody: \n Riding on ...
-Name: combined, dtype: object}
-I have found that there is no state law requiring helmet use, but some cities and counties do require helmets. I will now search for 'Section 21a' to find out if Orting is one of these cities or counties.
-
-running 2th step.
-= running tool retrieve_documents, with parameters:
-{'query': 'Section 21a'}
-== tool results:
-{'other_references_to_query': '- Section 3b',
- 'top_matched_document': 2 Title: Section 21a\nBody: helmet rules by loca...
-Name: combined, dtype: object}
-Yes, you do need to wear a helmet when riding a bike in Orting if you are under 17.
-```
+
+ running 0th step.
+ I will search for 'Orting' and 'bike helmet' to find the relevant information.
+
+ running 1th step.
+ = running tool retrieve_documents, with parameters:
+ {'query': 'Orting bike helmet'}
+ == tool results:
+ {'other_references_to_query': 'Section 21a, Section 3b',
+ 'top_matched_document': 0 Title: Bicycle law\nBody: \n Riding on ...
+ Name: combined, dtype: object}
+ I have found that there is no state law requiring helmet use, but some cities and counties do require helmets. I will now search for 'Section 21a' to find out if Orting is one of these cities or counties.
+
+ running 2th step.
+ = running tool retrieve_documents, with parameters:
+ {'query': 'Section 21a'}
+ == tool results:
+ {'other_references_to_query': '- Section 3b',
+ 'top_matched_document': 2 Title: Section 21a\nBody: helmet rules by loca...
+ Name: combined, dtype: object}
+ Yes, you do need to wear a helmet when riding a bike in Orting if you are under 17.
+
diff --git a/fern/pages/cookbooks/agentic-rag-mixed-data.mdx b/fern/pages/cookbooks/agentic-rag-mixed-data.mdx
index 6c7d3aa22..0e6acb612 100644
--- a/fern/pages/cookbooks/agentic-rag-mixed-data.mdx
+++ b/fern/pages/cookbooks/agentic-rag-mixed-data.mdx
@@ -3,7 +3,7 @@ title: Agentic RAG for PDFs with mixed data
slug: /page/agentic-rag-mixed-data
description: "This page describes building a powerful, multi-step chatbot with Cohere's models."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, chatbot"
---
@@ -14,38 +14,48 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Shaan Desai",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg"
+ }
]}
/>
-
-## Motivation
+
-Retrieval-augmented generation (RAG) allows language models to generate grounded answers to questions about documents. However, the complexity of the documents can significantly influence overall RAG performance. For instance, the documents may be PDFs that contain a mix of text and tables.
+
-More broadly, the implementation of a RAG pipeline - including parsing and chunking of documents, along with the embedding and retrieval of the chunks - is critical to the accuracy of grounded answers. Additionally, it is sometimes not sufficient to merely retrieve the answers; a user may want further postprocessing performed on the output. This use case would benefit from giving the model access to tools.
-## Objective
+## Motivation
+Asking questions over documents continues to be an important retrieval augmented generation (RAG) task. However, the document complexity can significantly influence overall RAG performance, particularly when the documents are PDFs that contain a mix of text and tables. Finding an optimal strategy to parse this information, chunk, embed and retrieve it is thus quite critical to obtaining accurate results. Furthermore, if the questions being asked over the retrieved documents require mathematical reasoning, then having a model that can validate those operations is quite useful.
-In this notebook, we will guide you through best practices for setting up a RAG pipeline to process documents that contain both tables and text. We will also demonstrate how to create a [ReAct](https://python.langchain.com/v0.1/docs/modules/agents/agent_types/react/) agent with a Cohere model, and then give the agent access to a RAG pipeline tool to improve accuracy. The general structure of the notebook is as follows:
+## Objective
+In this notebook we will guide you through the best practices of setting up a RAG pipeline to process documents that contain both tables and text. In addition, we will show you how to create a Cohere ReAct agent with access to a RAG pipeline tool to improve accuracy. The general structure of the nb is as follows:
-- individual components around parsing, retrieval and generation are covered for documents with mixed tabular and textual data
-- a class object is created that can be used to instantiate the pipeline with parametric input
-- the RAG pipeline is then used as a tool for a Cohere ReACT agent
+1. individual components around parsing, retrieval and generation are covered for documents with mixed tabular and textual data
+2. a class object is created that can be used to instantiate the pipeline with parametric input
+3. the RAG pipeline is then used as a tool for a cohere react agent
# Reference Documents
+we recommend the following as a guide on doing [semi-structured RAG](https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_Structured_RAG.ipynb)
-We recommend the following notebook as a guide to [semi-structured RAG](https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_Structured_RAG.ipynb).
+we recommend this notebook to explore various parsing techniques for [PDFs](https://github.com/cohere-ai/cohere-developer-experience/blob/main/notebooks/guides/Document_Parsing_For_Enterprises.ipynb)
-We also recommend the following notebook to explore various parsing techniques for [PDFs](https://github.com/cohere-ai/cohere-developer-experience/blob/main/notebooks/guides/Document_Parsing_For_Enterprises.ipynb).
+various langchain supported [parsers](https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf/)
-Various LangChain-supported parsers can be found [here](https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf/).
+## Table of Contents
+- Section 1
+ - [Parsing](#sec_step1)
+ - [Vector Store Setup](#sec_step2)
+ - [RAG Pipeline](#sec_step3)
+- Section 2
+ - [RAG Pipeline Class](#sec_step4)
+- Section 3
+ - [ReAct Agent with RAG Tool](#sec_step5)
## Install Dependencies
-```python PYTHON
+
+```python
# there may be other dependencies that will need installation
# ! pip install --quiet langchain langchain_cohere langchain_experimental
# !pip --quiet install faiss-cpu tiktoken
@@ -56,7 +66,8 @@ Various LangChain-supported parsers can be found [here](https://python.langchain
# !pip install chromadb
```
-```python PYTHON
+
+```python
# LLM
import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
@@ -78,23 +89,26 @@ import pandas as pd
from datasets import load_dataset
from joblib import Parallel, delayed
+
os.environ['COHERE_API_KEY'] = ""
```
-# Parsing [#sec_step1]
+
+# Parsing
To improve RAG performance on PDFs with mixed types (text and tables), we investigated a number of parsing and chunking strategies from various libraries:
+- PyPDFLoader (LC)
+- LlamaParse (Llama-Index)
+- Unstructured IO
-- [PyPDFLoader (LC)](https://api.python.langchain.com/en/latest/document_loaders/langchain_community.document_loaders.pdf.PyPDFLoader.html)
-- [LlamaParse](https://docs.llamaindex.ai/en/stable/llama_cloud/llama_parse/) (Llama-Index)
-- [Unstructured](https://unstructured.io/)
We have found that the best option for parsing is unstructured.io since the parser can:
-
- separate tables from text
- automatically chunk the tables and text by title during the parsing step so that similar elements are grouped
-```python PYTHON
+
+
+```python
# UNSTRUCTURED pdf loader
# Get elements
raw_pdf_elements = partition_pdf(
@@ -117,7 +131,14 @@ raw_pdf_elements = partition_pdf(
```
-```python PYTHON
+ This function will be deprecated in a future release and `unstructured` will simply use the DEFAULT_MODEL from `unstructured_inference.model.base` to set default model name
+ Some weights of the model checkpoint at microsoft/table-transformer-structure-recognition were not used when initializing TableTransformerForObjectDetection: ['model.backbone.conv_encoder.model.layer4.0.downsample.1.num_batches_tracked', 'model.backbone.conv_encoder.model.layer3.0.downsample.1.num_batches_tracked', 'model.backbone.conv_encoder.model.layer2.0.downsample.1.num_batches_tracked']
+ - This IS expected if you are initializing TableTransformerForObjectDetection from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
+ - This IS NOT expected if you are initializing TableTransformerForObjectDetection from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
+
+
+
+```python
# extract table and textual objects from parser
class Element(BaseModel):
type: str
@@ -140,25 +161,27 @@ text_elements = [e for e in categorized_elements if e.type == "text"]
print(len(text_elements))
```
-```txt title="Output"
-14
-24
-```
+ 14
+ 24
-# Vector Store Setup [#sec_step2]
-There are many options for setting up a vector store. Here, we show how to do so using [Chroma](https://www.trychroma.com/) and Langchain's Multi-vector retrieval.
-As the name implies, multi-vector retrieval allows us to store multiple vectors per document; for instance, for a single document chunk, one could keep embeddings for both the chunk itself, and a summary of that document. A summary may be able to distill more accurately what a chunk is about, leading to better retrieval.
+
+# Vector Store Setup
-You can read more about this here: https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector/
+There are many options to setup a vector store. Here we show how to set one up using Chroma and Langchains Multi-vector retrieval.
+We use multi-vector retrieval because oftentimes a summary may be able to distill more accurately what a chunk is about, leading to better retrieval.
-Below, we demonstrate the following process:
+You can read more about this here: https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector/
+The process is as follows:
- summaries of each chunk are embedded
- during inference, the multi-vector retrieval returns the full context document related to the summary
-```python PYTHON
+
+```python
+
co = cohere.Client()
+
def get_chat_output(message, preamble, chat_history, model, temp, documents=None):
return co.chat(
message=message,
@@ -187,9 +210,11 @@ def rerank_cohere(query, returned_documents,model:str="rerank-multilingual-v3.0"
```
-```python PYTHON
+
+```python
# generate table and text summaries
-prompt_text = """You are an assistant tasked with summarizing tables and text. \
+
+prompt_text = """You are an assistant tasked with summarizing tables and text. \
Give a concise summary of the table or text. Table or text chunk: {element}. Only provide the summary and no other text."""
table_prompts = [prompt_text.format(element=i.text) for i in table_elements]
@@ -200,7 +225,8 @@ tables = [i.text for i in table_elements]
texts = [i.text for i in text_elements]
```
-```python PYTHON
+
+```python
# The vectorstore to use to index the child chunks
vectorstore = Chroma(collection_name="summaries", embedding_function=CohereEmbeddings())
# The storage layer for the parent documents
@@ -230,15 +256,17 @@ retriever.vectorstore.add_documents(summary_tables)
retriever.docstore.mset(list(zip(table_ids, tables)))
```
-# RAG Pipeline [#sec_step3]
+
+# RAG Pipeline
-With our database in place, we can run queries against it. The query process can be broken down into the following steps:
+the query process can be broken down into the following steps:
-- augment the query, this really helps retrieve all the relevant information
-- use each augmented query to retrieve the top k docs and then rerank them
-- concatenate all the shortlisted/reranked docs and pass them to the generation model
+1. augment the query, this really helps retrieve all the relevant information
+2. use each augmented query to retrieve the top k docs and then rerank them
+3. concatenate all the shortlisted/reranked docs and pass them to the generation model
-```python PYTHON
+
+```python
def process_query(query, retriever):
"""Runs query augmentation, retrieval, rerank and final generation in one call."""
augmented_queries=co.chat(message=query,model='command-r-plus',temperature=0.2, search_queries_only=True)
@@ -253,9 +281,9 @@ def process_query(query, retriever):
else:
#no queries will be run through RAG
documents = None
-
+
preamble = """
-## Task & Context
+## Task & Context
You help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.
## Style Guide
@@ -264,8 +292,8 @@ Unless the user asks for a different style of answer, you should answer in full
model = 'command-r-plus'
temp = 0.2
-
-
+
+
response = co.chat(
message=query,
documents=documents,
@@ -275,18 +303,17 @@ Unless the user asks for a different style of answer, you should answer in full
)
final_answer_docs="""The final answer is from the documents below:
-
+
{docs}""".format(docs=str(response.documents))
final_answer = response.text
return final_answer, final_answer_docs
```
-## Example
+## Example
-We can now test out a query. In this example, the final answer can be found on page 12 of the PDF, which aligns with the response provided by the model:
-```python PYTHON
+```python
query = "what are the charges for services in 2022"
final_answer, final_answer_docs = process_query(query, retriever)
print(final_answer)
@@ -294,24 +321,27 @@ print(final_answer_docs)
chat_history=[{'role':"USER", 'message':query},{'role':"CHATBOT", 'message':f'The final answer is: {final_answer}.' + final_answer_docs}]
+
```
-```txt title="Output"
-The charges for services in 2022 were $5,266 million.
-The final answer is from the documents below:
+ The charges for services in 2022 were $5,266 million.
+ The final answer is from the documents below:
+
+ [{'id': 'doc_0', 'snippet': 'Program and General Revenues FY 2023 FY 2022 FY 2021 Category (in millions) Charges for Services (CS) $5,769 $5,266 $5,669 Operating Grants and Contributions (OGC) 27,935 31,757 28,109 Capital Grants and Contributions (CGC) 657 656 675 Real Estate Taxes (RET) 31,502 29,507 31,421 Sales and Use Taxes (SUT) 10,577 10,106 7,614 Personal Income Taxes (PIT) 15,313 15,520 15,795 Income Taxes, Other (ITO) 13,181 9,521 9,499 Other Taxes* (OT) 3,680 3,777 2,755 Investment Income* (II) 694 151 226 Unrestricted Federal and State Aid (UFSA) 234 549 108 Other* (O) Total Program and General Revenues - Primary Government 2,305 $110,250 $107,535 $104,176 708 725', 'title': 'chunk 0'}]
- [{'id': 'doc_0', 'snippet': 'Program and General Revenues FY 2023 FY 2022 FY 2021 Category (in millions) Charges for Services (CS) $5,769 $5,266 $5,669 Operating Grants and Contributions (OGC) 27,935 31,757 28,109 Capital Grants and Contributions (CGC) 657 656 675 Real Estate Taxes (RET) 31,502 29,507 31,421 Sales and Use Taxes (SUT) 10,577 10,106 7,614 Personal Income Taxes (PIT) 15,313 15,520 15,795 Income Taxes, Other (ITO) 13,181 9,521 9,499 Other Taxes* (OT) 3,680 3,777 2,755 Investment Income* (II) 694 151 226 Unrestricted Federal and State Aid (UFSA) 234 549 108 Other* (O) Total Program and General Revenues - Primary Government 2,305 $110,250 $107,535 $104,176 708 725', 'title': 'chunk 0'}]
-```
-### Chat History Management
+the final answer is correct based on page 12 in the PDF and we can see that the information retrieved is linked to that table :)
+
+### chat history management
-In the example below, we ask a follow up question that relies on the chat history, but does not require a rerun of the RAG pipeline.
+an example of asking a follow up question that relies on the chat history but does not require a re-run of RAG.
-We detect questions that do not require RAG by examining the `search_queries` object returned by calling `co.chat` to generate candidate queries to answer our question. If this object is empty, then the model has determined that a document query is not needed to answer the question.
+The search_queries_only flag can be used to determine whether RAG needs to be rerun or not i.e. it can help easily identify if the query passed needs retrieval.
-In the example below, the `else` statement is invoked based on `query2`. We still pass in the chat history, allowing the question to be answered with only the prior context.
+In the example below, the else statement is invoked based on query2. In the else we pass in history without documents as the new query does not need to call the RAG pipeline
-```python PYTHON
+
+```python
query2='divide this by two'
augmented_queries=co.chat(message=query2,model='command-r-plus',temperature=0.2, search_queries_only=True)
if augmented_queries.search_queries:
@@ -326,32 +356,34 @@ else:
chat_history=chat_history,
temperature=0.3
)
-
+
print("Final answer:")
print(response.text)
```
-```txt title="Output"
RAG is not needed
Final answer:
The result of dividing the charges for services in 2022 by two is $2,633.
-```
----
-# RAG Pipeline Class [#sec_step4]
+## ------------------------------------------------------- ##
+
+
+# RAG Pipeline Class
+
+Here we connect all the pieces discussed above into one class object that is then used as a tool for a cohere react agent. This class is to help consolidate and clarify the key parameters used to define the RAG pipeline.
-Here, we connect all of the pieces discussed above into one class object, which is then used as a tool for a Cohere ReAct agent. This class definition consolidates and clarify the key parameters used to define the RAG pipeline.
-```python PYTHON
+```python
co = cohere.Client()
```
-```python PYTHON
+
+```python
class Element(BaseModel):
type: str
text: Any
-
+
class RAG_pipeline():
def __init__(self,paths):
self.embedding_model="embed-english-v3.0"
@@ -362,12 +394,12 @@ class RAG_pipeline():
self.top_k_rerank=3
self.temperature=0.2
self.preamble="""
-## Task & Context
+## Task & Context
You help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.
## Style Guide
Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.
-"""
+"""
self.n_jobs=10 #number of parallel processes to run summarization of chunks
self.extract_images_in_pdf=False
self.infer_table_structure=True
@@ -378,7 +410,7 @@ Unless the user asks for a different style of answer, you should answer in full
self.image_output_dir_path='.'
self.paths = paths
self.parse_and_build_retriever()
-
+
def parse_and_build_retriever(self,):
#step1, parse pdfs
# if condition just for debugging since perf_audit.pdf is parsed in the prev step, no need to rerun
@@ -393,7 +425,7 @@ Unless the user asks for a different style of answer, you should answer in full
self.text_summaries=text_summaries
#setup the multivector retriever
self.make_retriever(tables, table_summaries, texts, text_summaries)
-
+
def extract_text_and_tables(self,parsed_pdf_list):
# extract table and textual objects from parser
# Categorize by type
@@ -406,11 +438,11 @@ Unless the user asks for a different style of answer, you should answer in full
categorized_elements.append(Element(type="table", text=str(element)))
elif "unstructured.documents.elements.CompositeElement" in str(type(element)):
categorized_elements.append(Element(type="text", text=str(element)))
-
+
# Tables
table_elements = [e for e in categorized_elements if e.type == "table"]
print(len(table_elements))
-
+
# Text
text_elements = [e for e in categorized_elements if e.type == "text"]
print(len(text_elements))
@@ -418,7 +450,7 @@ Unless the user asks for a different style of answer, you should answer in full
all_text_elements.extend(text_elements)
return all_table_elements, all_text_elements
-
+
def parse_pdfs(self, paths):
path_raw_elements = []
@@ -443,12 +475,12 @@ Unless the user asks for a different style of answer, you should answer in full
path_raw_elements.append(raw_pdf_elements)
print('PDFs parsed')
return path_raw_elements
-
+
def get_chat_output(self,message, preamble, model, temp):
# print("**message")
# print(message)
-
+
response=co.chat(
message=message,
preamble=preamble,
@@ -463,7 +495,7 @@ Unless the user asks for a different style of answer, you should answer in full
"""Parallel processing of chat endpoint calls."""
responses = Parallel(n_jobs=n_jobs, prefer="threads")(delayed(self.get_chat_output)(prompt,preamble,model,temp) for prompt in prompts)
return responses
-
+
def rerank_cohere(self,query, returned_documents,model, top_n):
response = co.rerank(
query=query,
@@ -478,9 +510,9 @@ Unless the user asks for a different style of answer, you should answer in full
def generate_summaries(self,table_elements,text_elements):
# generate table and text summaries
- summarize_prompt = """You are an assistant tasked with summarizing tables and text. \
+ summarize_prompt = """You are an assistant tasked with summarizing tables and text. \
Give a concise summary of the table or text. Table or text chunk: {element}. Only provide the summary and no other text."""
-
+
table_prompts = [summarize_prompt.format(element=i.text) for i in table_elements]
table_summaries = self.parallel_proc_chat(table_prompts,self.preamble,self.summary_model,self.temperature,self.n_jobs)
text_prompts = [summarize_prompt.format(element=i.text) for i in text_elements]
@@ -521,7 +553,7 @@ Unless the user asks for a different style of answer, you should answer in full
retriever.docstore.mset(list(zip(table_ids, tables)))
self.retriever = retriever
print('retriever built')
-
+
def process_query(self,query):
"""Runs query augmentation, retrieval, rerank and generation in one call."""
augmented_queries=co.chat(message=query,model=self.generation_model,temperature=self.temperature, search_queries_only=True)
@@ -535,7 +567,7 @@ Unless the user asks for a different style of answer, you should answer in full
documents = [{"title": f"chunk {i}", "snippet": reranked_docs[i]} for i in range(len(reranked_docs))]
else:
documents = None
-
+
response = co.chat(
message=query,
documents=documents,
@@ -543,40 +575,38 @@ Unless the user asks for a different style of answer, you should answer in full
model=self.generation_model,
temperature=self.temperature
)
-
+
final_answer_docs="""The final answer is from the documents below:
-
+
{docs}""".format(docs=str(response.documents))
-
+
final_answer = response.text
return final_answer, final_answer_docs
```
-```python PYTHON
+
+```python
rag_object=RAG_pipeline(paths=["city_ny_popular_fin_report.pdf"])
```
This function will be deprecated in a future release and `unstructured` will simply use the DEFAULT_MODEL from `unstructured_inference.model.base` to set default model name
-```txt title="Output"
-PDFs parsed
-14
-24
-summaries generated
-retriever built
-```
-# Cohere ReAct Agent with RAG Tool [#sec_step5]
+ PDFs parsed
+ 14
+ 24
+ summaries generated
+ retriever built
+
-Finally, we build a simple agent that utilizes the RAG pipeline defined above. We do this by granting the agent access to two tools:
+
+# Cohere REACT Agent with RAG Tool
-- the end-to-end RAG pipeline
-- a Python interpreter
+we build a simple agent using the RAG pipeline previously defined. The e2e rag pipeline is provided as a tool in addition to a python tool. The premise in coupling these tools is so that the mathematical steps can be done using a python tool to improve accuracy.
-The intention behind coupling these tools is to enable the model to perform mathematical and other postprocessing operations on RAG outputs using Python.
-```python PYTHON
+```python
from langchain.agents import Tool
from langchain_experimental.utilities import PythonREPL
from langchain.agents import AgentExecutor
@@ -591,20 +621,20 @@ class react_agent():
def __init__(self,rag_retriever,model="command-r-plus",temperature=0.2):
self.llm = ChatCohere(model=model, temperature=temperature)
self.preamble="""
-## Task & Context
+## Task & Context
You help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.
## Style Guide
Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.
## Guidelines
-You are an expert who answers the user's question.
+You are an expert who answers the user's question.
You have access to a vectorsearch tool that will use your query to search through documents and find the relevant answer.
You also have access to a python interpreter tool which you can use to run code for mathematical operations.
"""
self.get_tools(rag_retriever)
self.build_agent()
-
+
def get_tools(self,rag_retriever):
@tool
def vectorsearch(query: str):
@@ -617,7 +647,7 @@ You also have access to a python interpreter tool which you can use to run code
query: str = Field(description="the users query")
vectorsearch.args_schema = vectorsearch_inputs
-
+
python_repl = PythonREPL()
python_tool = Tool(
name="python_repl",
@@ -656,79 +686,90 @@ You also have access to a python interpreter tool which you can use to run code
"preamble": self.preamble,
})
return response
-
+
```
-```python PYTHON
+
+```python
agent_object=react_agent(rag_retriever=rag_object)
```
-```python PYTHON
+
+```python
step1_response=agent_object.run_agent("what are the charges for services in 2022 and 2023")
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will search for the charges for services in 2022 and 2023.
-{'tool_name': 'vectorsearch', 'parameters': {'query': 'charges for services in 2022 and 2023'}}
-[0m[36;1m[1;3mThe charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.The final answer is from the documents below:
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for the charges for services in 2022 and 2023.
+ {'tool_name': 'vectorsearch', 'parameters': {'query': 'charges for services in 2022 and 2023'}}
+ [0m[36;1m[1;3mThe charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.The final answer is from the documents below:
+
+ [{'id': 'doc_0', 'snippet': 'Program and General Revenues FY 2023 FY 2022 FY 2021 Category (in millions) Charges for Services (CS) $5,769 $5,266 $5,669 Operating Grants and Contributions (OGC) 27,935 31,757 28,109 Capital Grants and Contributions (CGC) 657 656 675 Real Estate Taxes (RET) 31,502 29,507 31,421 Sales and Use Taxes (SUT) 10,577 10,106 7,614 Personal Income Taxes (PIT) 15,313 15,520 15,795 Income Taxes, Other (ITO) 13,181 9,521 9,499 Other Taxes* (OT) 3,680 3,777 2,755 Investment Income* (II) 694 151 226 Unrestricted Federal and State Aid (UFSA) 234 549 108 Other* (O) Total Program and General Revenues - Primary Government 2,305 $110,250 $107,535 $104,176 708 725', 'title': 'chunk 0'}][0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.
+ Grounded answer: The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.[0m
+
+ [1m> Finished chain.[0m
- [{'id': 'doc_0', 'snippet': 'Program and General Revenues FY 2023 FY 2022 FY 2021 Category (in millions) Charges for Services (CS) $5,769 $5,266 $5,669 Operating Grants and Contributions (OGC) 27,935 31,757 28,109 Capital Grants and Contributions (CGC) 657 656 675 Real Estate Taxes (RET) 31,502 29,507 31,421 Sales and Use Taxes (SUT) 10,577 10,106 7,614 Personal Income Taxes (PIT) 15,313 15,520 15,795 Income Taxes, Other (ITO) 13,181 9,521 9,499 Other Taxes* (OT) 3,680 3,777 2,755 Investment Income* (II) 694 151 226 Unrestricted Federal and State Aid (UFSA) 234 549 108 Other* (O) Total Program and General Revenues - Primary Government 2,305 $110,250 $107,535 $104,176 708 725', 'title': 'chunk 0'}][0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.
-Grounded answer: The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.[0m
-[1m> Finished chain.[0m
-```
+Example of how to handle history with the langchain agent
-Just like earlier, we can also pass chat history to the LangChain agent to refer to for any other queries.
-```python PYTHON
+```python
from langchain_core.messages import HumanMessage, AIMessage
```
-```python PYTHON
+
+```python
chat_history=[
HumanMessage(content=step1_response['input']),
AIMessage(content=step1_response['output'])
]
```
-```python PYTHON
+
+```python
agent_object.run_agent("what is the mean of the two values",history=chat_history)
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
-Python REPL can execute arbitrary code. Use with caution.
+ Python REPL can execute arbitrary code. Use with caution.
+
+
+ [32;1m[1;3m
+ I will use the Python Interpreter tool to calculate the mean of the two values.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import numpy as np\n\n# Data\nvalues = [5266, 5769]\n\n# Calculate the mean\nmean_value = np.mean(values)\n\nprint(f"The mean of the two values is: {mean_value:.0f} million")'}}
+ [0m[33;1m[1;3mThe mean of the two values is: 5518 million
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The mean of the two values is 5518 million.
+ Grounded answer: The mean of the two values is 5518 million.[0m
+
+ [1m> Finished chain.[0m
+
-[32;1m[1;3m
-I will use the Python Interpreter tool to calculate the mean of the two values.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import numpy as np\n\n# Data\nvalues = [5266, 5769]\n\n# Calculate the mean\nmean_value = np.mean(values)\n\nprint(f"The mean of the two values is: {mean_value:.0f} million")'}}
-[0m[33;1m[1;3mThe mean of the two values is: 5518 million
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The mean of the two values is 5518 million.
-Grounded answer: The mean of the two values is 5518 million.[0m
-[1m> Finished chain.[0m
-```
-````python title="Output"
-{'input': 'what is the mean of the two values',
-'preamble': "\n## Task & Context\nYou help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.\n\n## Style Guide\nUnless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.\n\n## Guidelines\nYou are an expert who answers the user's question. \nYou have access to a vectorsearch tool that will use your query to search through documents and find the relevant answer.\nYou also have access to a python interpreter tool which you can use to run code for mathematical operations.\n",
-'chat_history': [HumanMessage(content='what are the charges for services in 2022 and 2023'),
-AIMessage(content='The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.')],
-'output': 'The mean of the two values is 5518 million.',
-'citations': [CohereCitation(start=30, end=42, text='5518 million', documents=[{'output': 'The mean of the two values is: 5518 million\n'}])],
-'intermediate_steps': [(AgentActionMessageLog(tool='python_interpreter', tool_input={'code': 'import numpy as np\n\n# Data\nvalues = [5266, 5769]\n\n# Calculate the mean\nmean_value = np.mean(values)\n\nprint(f"The mean of the two values is: {mean_value:.0f} million")'}, log='\nI will use the Python Interpreter tool to calculate the mean of the two values.\n{\'tool_name\': \'python_interpreter\', \'parameters\': {\'code\': \'import numpy as np\\n\\n# Data\\nvalues = [5266, 5769]\\n\\n# Calculate the mean\\nmean_value = np.mean(values)\\n\\nprint(f"The mean of the two values is: {mean_value:.0f} million")\'}}\n', message_log=[AIMessage(content='\nPlan: I will use the Python Interpreter tool to calculate the mean of the two values.\nAction: ```json\n[\n {\n "tool_name": "python_interpreter",\n "parameters": {\n "code": "import numpy as np\\n\\n# Data\\nvalues = [5266, 5769]\\n\\n# Calculate the mean\\nmean_value = np.mean(values)\\n\\nprint(f\\"The mean of the two values is: {mean_value:.0f} million\\")"\n }\n }\n]\n```')]),
-'The mean of the two values is: 5518 million\n')]}
-````
+ {'input': 'what is the mean of the two values',
+ 'preamble': "\n## Task & Context\nYou help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.\n\n## Style Guide\nUnless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.\n\n## Guidelines\nYou are an expert who answers the user's question. \nYou have access to a vectorsearch tool that will use your query to search through documents and find the relevant answer.\nYou also have access to a python interpreter tool which you can use to run code for mathematical operations.\n",
+ 'chat_history': [HumanMessage(content='what are the charges for services in 2022 and 2023'),
+ AIMessage(content='The charges for services in 2022 were $5,266 million and in 2023 were $5,769 million.')],
+ 'output': 'The mean of the two values is 5518 million.',
+ 'citations': [CohereCitation(start=30, end=42, text='5518 million', documents=[{'output': 'The mean of the two values is: 5518 million\n'}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='python_interpreter', tool_input={'code': 'import numpy as np\n\n# Data\nvalues = [5266, 5769]\n\n# Calculate the mean\nmean_value = np.mean(values)\n\nprint(f"The mean of the two values is: {mean_value:.0f} million")'}, log='\nI will use the Python Interpreter tool to calculate the mean of the two values.\n{\'tool_name\': \'python_interpreter\', \'parameters\': {\'code\': \'import numpy as np\\n\\n# Data\\nvalues = [5266, 5769]\\n\\n# Calculate the mean\\nmean_value = np.mean(values)\\n\\nprint(f"The mean of the two values is: {mean_value:.0f} million")\'}}\n', message_log=[AIMessage(content='\nPlan: I will use the Python Interpreter tool to calculate the mean of the two values.\nAction: ```json\n[\n {\n "tool_name": "python_interpreter",\n "parameters": {\n "code": "import numpy as np\\n\\n# Data\\nvalues = [5266, 5769]\\n\\n# Calculate the mean\\nmean_value = np.mean(values)\\n\\nprint(f\\"The mean of the two values is: {mean_value:.0f} million\\")"\n }\n }\n]\n```')]),
+ 'The mean of the two values is: 5518 million\n')]}
-# Conclusion
-As you can see, the RAG pipeline can be used as a tool for a Cohere ReAct agent. This allows the agent to access the RAG pipeline for document retrieval and generation, as well as a Python interpreter for postprocessing mathematical operations to improve accuracy. This setup can be used to improve the accuracy of grounded answers to questions about documents that contain both tables and text.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/analysis-of-financial-forms.mdx b/fern/pages/cookbooks/analysis-of-financial-forms.mdx
index d893c67f4..c70f7af77 100644
--- a/fern/pages/cookbooks/analysis-of-financial-forms.mdx
+++ b/fern/pages/cookbooks/analysis-of-financial-forms.mdx
@@ -3,7 +3,7 @@ title: Analysis of Form 10-K/10-Q Using Cohere and RAG
slug: /page/analysis-of-financial-forms
description: "This page describes how to use Cohere's large language models to build an agent able to analyze financial forms like a 10-K or a 10-Q."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI assistant for finance"
---
@@ -14,12 +14,14 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Alex Barbet",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/bf2c763-Alex.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/bf2c763-Alex.jpg"
+ }
]}
/>
-
+
+
+
## **Getting Started**
@@ -27,13 +29,15 @@ You may use this script to jumpstart financial analysis of 10-Ks or 10-Qs with C
This cookbook relies on helpful tooling from LlamaIndex, as well as our Cohere SDK. If you're familiar with LlamaIndex, it should be easy to slot this process into your own productivity flows.
-```python PYTHON
+
+```python
%%capture
!sudo apt install tesseract-ocr poppler-utils
!pip install "cohere<5" langchain llama-index llama-index-embeddings-cohere llama-index-postprocessor-cohere-rerank pytesseract pdf2image
```
-```python PYTHON
+
+```python
# Due to compatibility issues, we need to do imports like this
from llama_index.core.schema import TextNode
@@ -41,7 +45,8 @@ from llama_index.core.schema import TextNode
!pip install unstructured
```
-```python PYTHON
+
+```python
import cohere
from getpass import getpass
@@ -53,9 +58,18 @@ co = cohere.Client(COHERE_API_KEY)
```
-```txt title="Output"
-Enter your Cohere API key: ··········
-```
+
+
+
+
+
+
+ Enter your Cohere API key: ··········
+
## **Step 1: Loading a 10-K**
@@ -63,7 +77,8 @@ You may run the following cells to load a 10-K that has already been preprocesse
> 💡 If you'd like to run the OCR pipeline yourself, you can find more info in the section titled **PDF to Text using OCR and `pdf2image`**.
-```python PYTHON
+
+```python
# Using langchain here since they have access to the Unstructured Data Loader powered by unstructured.io
from langchain_community.document_loaders import UnstructuredURLLoader
@@ -79,11 +94,20 @@ edgar_10k = documents[0].page_content
nodes = [TextNode(text=document.page_content, id_=f"doc_{i}") for i, document in enumerate(documents)]
```
-```txt title="Output"
-[nltk_data] Downloading package averaged_perceptron_tagger to
-[nltk_data] /root/nltk_data...
-[nltk_data] Unzipping taggers/averaged_perceptron_tagger.zip.
-```
+
+
+
+
+
+
+ [nltk_data] Downloading package averaged_perceptron_tagger to
+ [nltk_data] /root/nltk_data...
+ [nltk_data] Unzipping taggers/averaged_perceptron_tagger.zip.
+
We'll need to convert the text into chunks of a certain size in order for the Cohere embedding model to properly ingest them down the line.
@@ -91,7 +115,8 @@ We choose to use LlamaIndex's `SentenceSplitter` in this case in order to get th
You may also apply further transformations from the LlamaIndex repo if you so choose. Take a look at the [docs](https://docs.llamaindex.ai/en/stable/understanding/loading/loading.html) for inspiration on what is possible with transformations.
-```python PYTHON
+
+```python
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core.node_parser import SentenceSplitter
@@ -114,52 +139,62 @@ pipeline = IngestionPipeline(
nodes = pipeline.run(nodes=nodes)
```
-```txt title="Output"
-/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:88: UserWarning:
-The secret `HF_TOKEN` does not exist in your Colab secrets.
-To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.
-You will be able to reuse this secret in all of your notebooks.
-Please note that authentication is recommended but still optional to access public models or datasets.
- warnings.warn(
+
-tokenizer_config.json: 0%| | 0.00/7.92k [00:00, ?B/s]
+ /usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:88: UserWarning:
+ The secret `HF_TOKEN` does not exist in your Colab secrets.
+ To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.
+ You will be able to reuse this secret in all of your notebooks.
+ Please note that authentication is recommended but still optional to access public models or datasets.
+ warnings.warn(
-tokenization_cohere_fast.py: 0%| | 0.00/43.7k [00:00, ?B/s]
+ tokenizer_config.json: 0%| | 0.00/7.92k [00:00, ?B/s]
-configuration_cohere.py: 0%| | 0.00/7.37k [00:00, ?B/s]
-A new version of the following files was downloaded from https://huggingface.co/CohereForAI/c4ai-command-r-v01:
-- configuration_cohere.py
-. Make sure to double-check they do not contain any added malicious code. To avoid downloading new versions of the code file, you can pin a revision.
-A new version of the following files was downloaded from https://huggingface.co/CohereForAI/c4ai-command-r-v01:
-- tokenization_cohere_fast.py
-- configuration_cohere.py
-. Make sure to double-check they do not contain any added malicious code. To avoid downloading new versions of the code file, you can pin a revision.
+ tokenization_cohere_fast.py: 0%| | 0.00/43.7k [00:00, ?B/s]
-tokenizer.json: 0%| | 0.00/12.8M [00:00, ?B/s]
+ configuration_cohere.py: 0%| | 0.00/7.37k [00:00, ?B/s]
+ A new version of the following files was downloaded from https://huggingface.co/CohereForAI/c4ai-command-r-v01:
+ - configuration_cohere.py
+ . Make sure to double-check they do not contain any added malicious code. To avoid downloading new versions of the code file, you can pin a revision.
+ A new version of the following files was downloaded from https://huggingface.co/CohereForAI/c4ai-command-r-v01:
+ - tokenization_cohere_fast.py
+ - configuration_cohere.py
+ . Make sure to double-check they do not contain any added malicious code. To avoid downloading new versions of the code file, you can pin a revision.
-special_tokens_map.json: 0%| | 0.00/429 [00:00, ?B/s]
-Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
-```
+ tokenizer.json: 0%| | 0.00/12.8M [00:00, ?B/s]
+
+
+
+ special_tokens_map.json: 0%| | 0.00/429 [00:00, ?B/s]
+
+
+ Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
+
## **Step 2: Load document into a LlamaIndex vector store**
Loading the document into a LlamaIndex vector store will allow us to use the Cohere embedding model and rerank model to retrieve the relevant parts of the form to pass into Command.
-```python PYTHON
+
+```python
from llama_index.core import Settings, VectorStoreIndex
from llama_index.postprocessor.cohere_rerank import CohereRerank
@@ -185,13 +220,24 @@ rerank = CohereRerank(api_key=COHERE_API_KEY, top_n=15)
retrieve = lambda query: rerank.postprocess_nodes(retriever.retrieve(query), query_str=query)
```
+
+
+
+
+
+
## **Step 3: Query generation and retrieval**
In order to do RAG, we need a query or a set of queries to actually _do_ the retrieval step. As is standard in RAG settings, we'll use Command to generate those queries for us. Then, we'll use those queries along with the LlamaIndex retriever we built earlier to retrieve the most relevant pieces of the 10-K.
To learn more about document mode and query generation, check out [our documentation](https://docs.cohere.com/docs/retrieval-augmented-generation-rag).
-```python PYTHON
+
+```python
PROMPT = "List the overall revenue numbers for 2021, 2022, and 2023 in the 10-K as bullet points, then explain the revenue growth trends."
# Get queries to run against our index from the command-nightly model
@@ -202,9 +248,20 @@ else:
print("No queries returned by the model")
```
+
+
+
+
+
+
Now, with the queries in hand, we search against our vector index.
-```python PYTHON
+
+```python
# Convenience function for formatting documents
def format_for_cohere_client(nodes_):
return [
@@ -228,6 +285,16 @@ for query in queries:
documents = [dict(t, id=f"doc_{i}") for i, t in enumerate({tuple(d.items()) for d in documents})]
```
+
+
+
+
+
+
## **Step 4: Make a RAG request to Command using document mode**
Now that we have our nicely formatted chunks from the 10-K, we can pass them directly into Command using the Cohere SDK. By passing the chunks into the `documents` kwarg, we enable document mode, which will perform grounded inference on the documents you pass in.
@@ -236,7 +303,8 @@ You can see this for yourself by inspecting the `response.citations` field to ch
You can learn more about the `chat` endpoint by checking out the API reference [here](https://docs.cohere.com/reference/chat).
-```python PYTHON
+
+```python
# Make a request to the model
response = co.chat(
message=PROMPT,
@@ -249,20 +317,30 @@ response = co.chat(
print(response.text)
```
-```txt title="Output"
-Here are the overall revenue numbers for the years 2021, 2022, and 2023 as bullet points:
-- 2021: $5,992 million
-- 2022: $8,399 million
-- 2023: $9,917 million
-Revenue increased by 18% in 2023 compared to 2022, primarily due to a 14% increase in Nights and Experiences Booked, which reached 54.5 million. This, combined with higher average daily rates, resulted in a 16% increase in Gross Booking Value, which reached $10.0 billion.
-The revenue growth trend demonstrates sustained strong travel demand. On a constant-currency basis, revenue increased by 17% in 2023 compared to the previous year.
+
-Other factors influencing the company's financial performance are described outside of the revenue growth trends.
-```
-```python PYTHON
+
+ Here are the overall revenue numbers for the years 2021, 2022, and 2023 as bullet points:
+ - 2021: $5,992 million
+ - 2022: $8,399 million
+ - 2023: $9,917 million
+
+ Revenue increased by 18% in 2023 compared to 2022, primarily due to a 14% increase in Nights and Experiences Booked, which reached 54.5 million. This, combined with higher average daily rates, resulted in a 16% increase in Gross Booking Value, which reached $10.0 billion.
+
+ The revenue growth trend demonstrates sustained strong travel demand. On a constant-currency basis, revenue increased by 17% in 2023 compared to the previous year.
+
+ Other factors influencing the company's financial performance are described outside of the revenue growth trends.
+
+
+
+```python
# Helper function for displaying response WITH citations
def insert_citations(text: str, citations: list[dict]):
"""
@@ -291,18 +369,27 @@ def insert_citations(text: str, citations: list[dict]):
print(insert_citations(response.text, response.citations))
```
-```txt title="Output"
-Here are the overall revenue numbers for the years 2021, 2022, and 2023 as bullet points:
-- 2021: $5,992 million [13]
-- 2022: $8,399 million [13]
-- 2023: $9,917 million [13]
-Revenue increased by 18% in 2023 [11] compared to 2022, primarily due to a 14% increase in Nights and Experiences Booked [11], which reached 54.5 million. [11] This, combined with higher average daily rates [11], resulted in a 16% increase in Gross Booking Value [11], which reached $10.0 billion. [11]
-The revenue growth trend demonstrates sustained strong travel demand. [11] On a constant-currency basis [11], revenue increased by 17% in 2023 [11] compared to the previous year.
+
+
+
+
+ Here are the overall revenue numbers for the years 2021, 2022, and 2023 as bullet points:
+ - 2021: $5,992 million [13]
+ - 2022: $8,399 million [13]
+ - 2023: $9,917 million [13]
+
+ Revenue increased by 18% in 2023 [11] compared to 2022, primarily due to a 14% increase in Nights and Experiences Booked [11], which reached 54.5 million. [11] This, combined with higher average daily rates [11], resulted in a 16% increase in Gross Booking Value [11], which reached $10.0 billion. [11]
+
+ The revenue growth trend demonstrates sustained strong travel demand. [11] On a constant-currency basis [11], revenue increased by 17% in 2023 [11] compared to the previous year.
+
+ Other factors [8, 14] influencing the company's financial performance are described outside of the revenue growth trends. [8, 14]
-Other factors [8, 14] influencing the company's financial performance are described outside of the revenue growth trends. [8, 14]
-```
# **Appendix**
@@ -316,7 +403,8 @@ To go from PDF to text with PyTesseract, there is an intermediary step of conver
To do this, we use `pdf2image`, which uses `poppler` behind the scenes to convert the PDF into a PNG. From there, we can pass the image (which is a PIL Image object) directly into the OCR tool.
-```python PYTHON
+
+```python
import pytesseract
from pdf2image import convert_from_path
@@ -330,7 +418,8 @@ pages = [pytesseract.image_to_string(page) for page in pages]
## Token count / price comparison and latency
-```python PYTHON
+
+```python
def get_response(prompt, rag):
if rag:
# Get queries to run against our index from the command-nightly model
@@ -368,7 +457,18 @@ def get_response(prompt, rag):
return response
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
prompt_template = """# financial form 10-K
{tenk}
@@ -378,39 +478,106 @@ prompt_template = """# financial form 10-K
full_context_prompt = prompt_template.format(tenk=edgar_10k, question=PROMPT)
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
r1 = get_response(PROMPT, rag=True)
r2 = get_response(full_context_prompt, rag=False)
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
def get_price(r):
return (r.token_count["prompt_tokens"] * 0.5 / 10e6) + (r.token_count["response_tokens"] * 1.5 / 10e6)
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
rag_price = get_price(r1)
full_context_price = get_price(r2)
print(f"RAG is {(full_context_price - rag_price) / full_context_price:.0%} cheaper than full context")
```
-```txt title="Output"
-RAG is 93% cheaper than full context
-```
-```python PYTHON
+
+
+
+
+
+ RAG is 93% cheaper than full context
+
+
+
+```python
%timeit get_response(PROMPT, rag=True)
```
-```txt title="Output"
-14.9 s ± 1.4 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
-```
-```python PYTHON
+
+
+
+
+
+ 14.9 s ± 1.4 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
+
+
+
+```python
%timeit get_response(full_context_prompt, rag=False)
```
-```txt title="Output"
-22.7 s ± 7.43 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
+
+
+
+
+
+
+ 22.7 s ± 7.43 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
+
+
+
+```python
+
```
diff --git a/fern/pages/cookbooks/analyzing-hacker-news.mdx b/fern/pages/cookbooks/analyzing-hacker-news.mdx
index 6307b1c11..39f6978b9 100644
--- a/fern/pages/cookbooks/analyzing-hacker-news.mdx
+++ b/fern/pages/cookbooks/analyzing-hacker-news.mdx
@@ -1,98 +1,104 @@
---
-title: Analyzing Hacker News with Cohere
+title: Analyzing Hacker News with Six Language Understanding Methods
slug: /page/analyzing-hacker-news
description: "This page describes building a generative-AI powered tool to analyze headlines with Cohere."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, analyzing text with a large language model."
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
+
+
+
Large language models give machines a vastly improved representation and understanding of language. These abilities give developers more options for content recommendation, analysis, and filtering.
In this notebook we take thousands of the most popular posts from Hacker News and demonstrate some of these functionalities:
1. Given an existing post title, retrieve the most similar posts (nearest neighbor search using embeddings)
-2. Given a query that we write, retrieve the most similar posts
-3. Plot the archive of articles by similarity (where similar posts are close together and different ones are far)
-4. Cluster the posts to identify the major common themes
-5. Extract major keywords from each cluster so we can identify what the clsuter is about
-6. (Experimental) Name clusters with a generative language model
+1. Given a query that we write, retrieve the most similar posts
+1. Plot the archive of articles by similarity (where similar posts are close together and different ones are far)
+1. Cluster the posts to identify the major common themes
+1. Extract major keywords from each cluster so we can identify what the clsuter is about
+1. (Experimental) Name clusters with a generative language model
## Setup
-
Let's start by installing the tools we'll need and then importing them.
-```python PYTHON
-!pip install cohere umap-learn altair annoy bertopic
-```
-```
-Requirement already satisfied: cohere in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (5.1.5)
-Requirement already satisfied: umap-learn in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (0.5.5)
-Requirement already satisfied: altair in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (5.2.0)
-Requirement already satisfied: annoy in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (1.17.3)
-Requirement already satisfied: bertopic in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (0.16.0)
-Requirement already satisfied: httpx>=0.21.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (0.27.0)
-Requirement already satisfied: pydantic>=1.9.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (2.6.0)
-Requirement already satisfied: typing_extensions>=4.0.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (4.10.0)
-Requirement already satisfied: numpy>=1.17 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.24.3)
-Requirement already satisfied: scipy>=1.3.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.11.1)
-Requirement already satisfied: scikit-learn>=0.22 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.3.0)
-Requirement already satisfied: numba>=0.51.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (0.57.0)
-Requirement already satisfied: pynndescent>=0.5 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (0.5.12)
-Requirement already satisfied: tqdm in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (4.65.0)
-Requirement already satisfied: jinja2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (3.1.2)
-Requirement already satisfied: jsonschema>=3.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (4.17.3)
-Requirement already satisfied: packaging in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (23.2)
-Requirement already satisfied: pandas>=0.25 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (2.0.3)
-Requirement already satisfied: toolz in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (0.12.0)
-Requirement already satisfied: hdbscan>=0.8.29 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (0.8.33)
-Requirement already satisfied: sentence-transformers>=0.4.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (2.6.1)
-Requirement already satisfied: plotly>=4.7.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (5.9.0)
-Requirement already satisfied: cython<3,>=0.27 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from hdbscan>=0.8.29->bertopic) (0.29.37)
-Requirement already satisfied: joblib>=1.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from hdbscan>=0.8.29->bertopic) (1.2.0)
-Requirement already satisfied: anyio in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (3.5.0)
-Requirement already satisfied: certifi in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (2023.11.17)
-Requirement already satisfied: httpcore==1.* in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (1.0.2)
-Requirement already satisfied: idna in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (3.4)
-Requirement already satisfied: sniffio in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (1.2.0)
-Requirement already satisfied: h11<0.15,>=0.13 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpcore==1.*->httpx>=0.21.2->cohere) (0.14.0)
-Requirement already satisfied: attrs>=17.4.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jsonschema>=3.0->altair) (22.1.0)
-Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jsonschema>=3.0->altair) (0.18.0)
-Requirement already satisfied: llvmlite<0.41,>=0.40.0dev0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from numba>=0.51.2->umap-learn) (0.40.0)
-Requirement already satisfied: python-dateutil>=2.8.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2.8.2)
-Requirement already satisfied: pytz>=2020.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2023.3.post1)
-Requirement already satisfied: tzdata>=2022.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2023.3)
-Requirement already satisfied: tenacity>=6.2.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from plotly>=4.7.0->bertopic) (8.2.2)
-Requirement already satisfied: annotated-types>=0.4.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pydantic>=1.9.2->cohere) (0.6.0)
-Requirement already satisfied: pydantic-core==2.16.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pydantic>=1.9.2->cohere) (2.16.1)
-Requirement already satisfied: threadpoolctl>=2.0.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from scikit-learn>=0.22->umap-learn) (2.2.0)
-Requirement already satisfied: transformers<5.0.0,>=4.32.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (4.39.3)
-Requirement already satisfied: torch>=1.11.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (2.2.2)
-Requirement already satisfied: huggingface-hub>=0.15.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (0.22.2)
-Requirement already satisfied: Pillow in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (10.0.1)
-Requirement already satisfied: MarkupSafe>=2.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jinja2->altair) (2.1.1)
-Requirement already satisfied: filelock in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (3.9.0)
-Requirement already satisfied: fsspec>=2023.5.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (2024.3.1)
-Requirement already satisfied: pyyaml>=5.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (6.0)
-Requirement already satisfied: requests in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (2.31.0)
-Requirement already satisfied: six>=1.5 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas>=0.25->altair) (1.16.0)
-Requirement already satisfied: sympy in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (1.11.1)
-Requirement already satisfied: networkx in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (3.1)
-Requirement already satisfied: regex!=2019.12.17 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (2022.7.9)
-Requirement already satisfied: tokenizers<0.19,>=0.14 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (0.15.2)
-Requirement already satisfied: safetensors>=0.4.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (0.4.2)
-Requirement already satisfied: charset-normalizer<4,>=2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from requests->huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (3.3.2)
-Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from requests->huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (1.26.18)
-Requirement already satisfied: mpmath>=0.19 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sympy->torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (1.3.0)
+```python
+!pip install cohere umap-learn altair annoy bertopic
```
-```python PYTHON
+ Requirement already satisfied: cohere in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (5.1.5)
+ Requirement already satisfied: umap-learn in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (0.5.5)
+ Requirement already satisfied: altair in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (5.2.0)
+ Requirement already satisfied: annoy in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (1.17.3)
+ Requirement already satisfied: bertopic in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (0.16.0)
+ Requirement already satisfied: httpx>=0.21.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (0.27.0)
+ Requirement already satisfied: pydantic>=1.9.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (2.6.0)
+ Requirement already satisfied: typing_extensions>=4.0.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from cohere) (4.10.0)
+ Requirement already satisfied: numpy>=1.17 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.24.3)
+ Requirement already satisfied: scipy>=1.3.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.11.1)
+ Requirement already satisfied: scikit-learn>=0.22 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (1.3.0)
+ Requirement already satisfied: numba>=0.51.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (0.57.0)
+ Requirement already satisfied: pynndescent>=0.5 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (0.5.12)
+ Requirement already satisfied: tqdm in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from umap-learn) (4.65.0)
+ Requirement already satisfied: jinja2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (3.1.2)
+ Requirement already satisfied: jsonschema>=3.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (4.17.3)
+ Requirement already satisfied: packaging in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (23.2)
+ Requirement already satisfied: pandas>=0.25 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (2.0.3)
+ Requirement already satisfied: toolz in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from altair) (0.12.0)
+ Requirement already satisfied: hdbscan>=0.8.29 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (0.8.33)
+ Requirement already satisfied: sentence-transformers>=0.4.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (2.6.1)
+ Requirement already satisfied: plotly>=4.7.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from bertopic) (5.9.0)
+ Requirement already satisfied: cython<3,>=0.27 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from hdbscan>=0.8.29->bertopic) (0.29.37)
+ Requirement already satisfied: joblib>=1.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from hdbscan>=0.8.29->bertopic) (1.2.0)
+ Requirement already satisfied: anyio in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (3.5.0)
+ Requirement already satisfied: certifi in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (2023.11.17)
+ Requirement already satisfied: httpcore==1.* in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (1.0.2)
+ Requirement already satisfied: idna in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (3.4)
+ Requirement already satisfied: sniffio in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpx>=0.21.2->cohere) (1.2.0)
+ Requirement already satisfied: h11<0.15,>=0.13 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from httpcore==1.*->httpx>=0.21.2->cohere) (0.14.0)
+ Requirement already satisfied: attrs>=17.4.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jsonschema>=3.0->altair) (22.1.0)
+ Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jsonschema>=3.0->altair) (0.18.0)
+ Requirement already satisfied: llvmlite<0.41,>=0.40.0dev0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from numba>=0.51.2->umap-learn) (0.40.0)
+ Requirement already satisfied: python-dateutil>=2.8.2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2.8.2)
+ Requirement already satisfied: pytz>=2020.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2023.3.post1)
+ Requirement already satisfied: tzdata>=2022.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pandas>=0.25->altair) (2023.3)
+ Requirement already satisfied: tenacity>=6.2.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from plotly>=4.7.0->bertopic) (8.2.2)
+ Requirement already satisfied: annotated-types>=0.4.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pydantic>=1.9.2->cohere) (0.6.0)
+ Requirement already satisfied: pydantic-core==2.16.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from pydantic>=1.9.2->cohere) (2.16.1)
+ Requirement already satisfied: threadpoolctl>=2.0.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from scikit-learn>=0.22->umap-learn) (2.2.0)
+ Requirement already satisfied: transformers<5.0.0,>=4.32.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (4.39.3)
+ Requirement already satisfied: torch>=1.11.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (2.2.2)
+ Requirement already satisfied: huggingface-hub>=0.15.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (0.22.2)
+ Requirement already satisfied: Pillow in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sentence-transformers>=0.4.1->bertopic) (10.0.1)
+ Requirement already satisfied: MarkupSafe>=2.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from jinja2->altair) (2.1.1)
+ Requirement already satisfied: filelock in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (3.9.0)
+ Requirement already satisfied: fsspec>=2023.5.0 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (2024.3.1)
+ Requirement already satisfied: pyyaml>=5.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (6.0)
+ Requirement already satisfied: requests in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (2.31.0)
+ Requirement already satisfied: six>=1.5 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas>=0.25->altair) (1.16.0)
+ Requirement already satisfied: sympy in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (1.11.1)
+ Requirement already satisfied: networkx in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (3.1)
+ Requirement already satisfied: regex!=2019.12.17 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (2022.7.9)
+ Requirement already satisfied: tokenizers<0.19,>=0.14 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (0.15.2)
+ Requirement already satisfied: safetensors>=0.4.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from transformers<5.0.0,>=4.32.0->sentence-transformers>=0.4.1->bertopic) (0.4.2)
+ Requirement already satisfied: charset-normalizer<4,>=2 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from requests->huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (3.3.2)
+ Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from requests->huggingface-hub>=0.15.1->sentence-transformers>=0.4.1->bertopic) (1.26.18)
+ Requirement already satisfied: mpmath>=0.19 in /Users/alexiscook/anaconda3/lib/python3.11/site-packages (from sympy->torch>=1.11.0->sentence-transformers>=0.4.1->bertopic) (1.3.0)
+
+
+
+```python
import cohere
import numpy as np
import pandas as pd
@@ -108,144 +114,167 @@ warnings.filterwarnings('ignore')
pd.set_option('display.max_colwidth', None)
```
-Fill in your Cohere API key in the next cell. To do this, begin by [signing up to Cohere](https://dashboard.cohere.com/) (for free!) if you haven't yet. Then get your API key [here](https://dashboard.cohere.com/api-keys).
+Fill in your Cohere API key in the next cell. To do this, begin by [signing up to Cohere](https://os.cohere.ai/) (for free!) if you haven't yet. Then get your API key [here](https://dashboard.cohere.com/api-keys).
+
-```python PYTHON
+```python
+# Paste your API key here. Remember to not share publicly
co = cohere.Client("COHERE_API_KEY") # Insert your Cohere API key
```
## Dataset: Top 3,000 Ask HN posts
-
We will use the top 3,000 posts from the Ask HN section of Hacker News. We provide a CSV containing the posts.
-```python PYTHON
+
+```python
+# Load the dataframe containing the text and metadata of the posts
df = pd.read_csv('https://storage.googleapis.com/cohere-assets/blog/text-clustering/data/askhn3k_df.csv', index_col=0)
print(f'Loaded a DataFrame with {len(df)} rows')
```
-```
-Loaded a DataFrame with 3000 rows
-```
+ Loaded a DataFrame with 3000 rows
+
-```python PYTHON
+
+```python
+# Let's glance at the contents of the dataframe with the text and metadata
df.head()
```
+
+
+
-
-
-
- |
-title |
-url |
-text |
-dead |
-by |
-score |
-time |
-timestamp |
-type |
-id |
-parent |
-descendants |
-ranking |
-deleted |
-
-
-
-
-0 |
-I'm a software engineer going blind, how should I prepare? |
-NaN |
+
+
+
+
+ |
+ title |
+ url |
+ text |
+ dead |
+ by |
+ score |
+ time |
+ timestamp |
+ type |
+ id |
+ parent |
+ descendants |
+ ranking |
+ deleted |
+
+
+
+
+ 0 |
+ I'm a software engineer going blind, how should I prepare? |
+ NaN |
I'm a 24 y/o full stack engineer (I know some of you are rolling your eyes right now, just highlighting that I have experience on frontend apps as well as backend architecture). I've been working professionally for ~7 years building mostly javascript projects but also some PHP. Two years ago I was diagnosed with a condition called "Usher's Syndrome" - characterized by hearing loss, balance issues, and progressive vision loss.<p>I know there are blind software engineers out there. My main questions are:<p>- Are there blind frontend engineers?<p>- What kinds of software engineering lend themselves to someone with limited vision? Backend only?<p>- Besides a screen reader, what are some of the best tools for building software with limited vision?<p>- Does your company employ blind engineers? How well does it work? What kind of engineer are they?<p>I'm really trying to get ahead of this thing and prepare myself as my vision is degrading rather quickly. I'm not sure what I can do if I can't do SE as I don't have any formal education in anything. I've worked really hard to get to where I am and don't want it to go to waste.<p>Thank you for any input, and stay safe out there!<p>Edit:<p>Thank you all for your links, suggestions, and moral support, I really appreciate it. Since my diagnosis I've slowly developed a crippling anxiety centered around a feeling that I need to figure out the rest of my life before it's too late. I know I shouldn't think this way but it is hard not to. I'm very independent and I feel a pressure to "show up." I will look into these opportunities mentioned and try to get in touch with some more members of the blind engineering community. |
-NaN |
-zachrip |
-3270 |
-1587332026 |
-2020-04-19 21:33:46+00:00 |
-story |
-22918980 |
-NaN |
-473.0 |
-NaN |
-NaN |
-
-
-1 |
-Am I the longest-serving programmer – 57 years and counting? |
-NaN |
-In May of 1963, I started my first full-time job as a computer programmer for Mitchell Engineering Company, a supplier of steel buildings. At Mitchell, I developed programs in Fortran II on an IBM 1620 mostly to improve the efficiency of order processing and fulfillment. Since then, all my jobs for the past 57 years have involved computer programming. I am now a data scientist developing cloud-based big data fraud detection algorithms using machine learning and other advanced analytical technologies. Along the way, I earned a Master’s in Operations Research and a Master’s in Management Science, studied artificial intelligence for 3 years in a Ph.D. program for engineering, and just two years ago I received Graduate Certificates in Big Data Analytics from the schools of business and computer science at a local university (FAU). In addition, I currently hold the designation of Certified Analytics Professional (CAP). At 74, I still have no plans to retire or to stop programming. |
-NaN |
-genedangelo |
-2634 |
-1590890024 |
-2020-05-31 01:53:44+00:00 |
-story |
-23366546 |
-NaN |
-531.0 |
-NaN |
-NaN |
-
-
-2 |
-Is S3 down? |
-NaN |
- I'm getting<p>\{\n "errorCode" : "InternalError"\n}<p>When I attempt to use the AWS Console to view s3 |
-NaN |
-iamdeedubs |
-2589 |
-1488303958 |
-2017-02-28 17:45:58+00:00 |
-story |
-13755673 |
-NaN |
-1055.0 |
-NaN |
-NaN |
-
-
-3 |
-What tech job would let me get away with the least real work possible? |
-NaN |
+ NaN |
+ zachrip |
+ 3270 |
+ 1587332026 |
+ 2020-04-19 21:33:46+00:00 |
+ story |
+ 22918980 |
+ NaN |
+ 473.0 |
+ NaN |
+ NaN |
+
+
+ 1 |
+ Am I the longest-serving programmer – 57 years and counting? |
+ NaN |
+ In May of 1963, I started my first full-time job as a computer programmer for Mitchell Engineering Company, a supplier of steel buildings. At Mitchell, I developed programs in Fortran II on an IBM 1620 mostly to improve the efficiency of order processing and fulfillment. Since then, all my jobs for the past 57 years have involved computer programming. I am now a data scientist developing cloud-based big data fraud detection algorithms using machine learning and other advanced analytical technologies. Along the way, I earned a Master’s in Operations Research and a Master’s in Management Science, studied artificial intelligence for 3 years in a Ph.D. program for engineering, and just two years ago I received Graduate Certificates in Big Data Analytics from the schools of business and computer science at a local university (FAU). In addition, I currently hold the designation of Certified Analytics Professional (CAP). At 74, I still have no plans to retire or to stop programming. |
+ NaN |
+ genedangelo |
+ 2634 |
+ 1590890024 |
+ 2020-05-31 01:53:44+00:00 |
+ story |
+ 23366546 |
+ NaN |
+ 531.0 |
+ NaN |
+ NaN |
+
+
+ 2 |
+ Is S3 down? |
+ NaN |
+ I'm getting<p>{\n "errorCode" : "InternalError"\n}<p>When I attempt to use the AWS Console to view s3 |
+ NaN |
+ iamdeedubs |
+ 2589 |
+ 1488303958 |
+ 2017-02-28 17:45:58+00:00 |
+ story |
+ 13755673 |
+ NaN |
+ 1055.0 |
+ NaN |
+ NaN |
+
+
+ 3 |
+ What tech job would let me get away with the least real work possible? |
+ NaN |
Hey HN,<p>I'll probably get a lot of flak for this. Sorry.<p>I'm an average developer looking for ways to work as little as humanely possible.<p>The pandemic made me realize that I do not care about working anymore. The software I build is useless. Time flies real fast and I have to focus on my passions (which are not monetizable).<p>Unfortunately, I require shelter, calories and hobby materials. Thus the need for some kind of job.<p>Which leads me to ask my fellow tech workers, what kind of job (if any) do you think would fit the following requirements :<p>- No / very little involvement in the product itself (I do not care.)<p>- Fully remote (You can't do much when stuck in the office. Ideally being done in 2 hours in the morning then chilling would be perfect.)<p>- Low expectactions / vague job description.<p>- Salary can be on the lower side.<p>- No career advancement possibilities required. Only tech, I do not want to manage people.<p>- Can be about helping other developers, setting up infrastructure/deploy or pure data management since this is fun.<p>I think the only possible jobs would be some kind of backend-only dev or devops/sysadmin work. But I'm not sure these exist anymore, it seems like you always end up having to think about the product itself. Web dev jobs always required some involvement in the frontend.<p>Thanks for any advice (or hate, which I can't really blame you for). |
-NaN |
-lmueongoqx |
-2022 |
-1617784863 |
-2021-04-07 08:41:03+00:00 |
-story |
-26721951 |
-NaN |
-1091.0 |
-NaN |
-NaN |
-
-
-4 |
-What books changed the way you think about almost everything? |
-NaN |
-I was reflecting today about how often I think about Freakonomics. I don't study it religiously. I read it one time more than 10 years ago. I can only remember maybe a single specific anecdote from the book. And yet the simple idea that basically every action humans take can be traced back to an incentive has fundamentally changed the way I view the world. Can anyone recommend books that have had a similar impact on them? |
-NaN |
-anderspitman |
-2009 |
-1549387905 |
-2019-02-05 17:31:45+00:00 |
-story |
-19087418 |
-NaN |
-1165.0 |
-NaN |
-NaN |
-
-
+ NaN |
+ lmueongoqx |
+ 2022 |
+ 1617784863 |
+ 2021-04-07 08:41:03+00:00 |
+ story |
+ 26721951 |
+ NaN |
+ 1091.0 |
+ NaN |
+ NaN |
+
+
+ 4 |
+ What books changed the way you think about almost everything? |
+ NaN |
+ I was reflecting today about how often I think about Freakonomics. I don't study it religiously. I read it one time more than 10 years ago. I can only remember maybe a single specific anecdote from the book. And yet the simple idea that basically every action humans take can be traced back to an incentive has fundamentally changed the way I view the world. Can anyone recommend books that have had a similar impact on them? |
+ NaN |
+ anderspitman |
+ 2009 |
+ 1549387905 |
+ 2019-02-05 17:31:45+00:00 |
+ story |
+ 19087418 |
+ NaN |
+ 1165.0 |
+ NaN |
+ NaN |
+
+
+
+
We calculate the embeddings using Cohere's `embed-english-v3.0` model. The resulting embeddings matrix has 3,000 rows (one for each post) and 1024 columns (meaning each post title is represented with a 1024-dimensional embedding).
-```python PYTHON
+
+```python
batch_size = 90
embeds_list = []
@@ -261,16 +290,21 @@ embeds = np.array(embeds_list)
embeds.shape
```
-```
-(3000, 1024)
-```
-## Building a semantic search index
+
+ (3000, 1024)
+
+
+
+## Building a semantic search index
For nearest-neighbor search, we can use the open-source Annoy library. Let's create a semantic search index and feed it all the embeddings.
-```python PYTHON
+
+```python
+# Create the search index, pass the size of embedding
search_index = AnnoyIndex(embeds.shape[1], 'angular')
+# Add all the vectors to the search index
for i in range(len(embeds)):
search_index.add_item(i, embeds[i])
@@ -278,20 +312,26 @@ search_index.build(10) # 10 trees
search_index.save('askhn.ann')
```
-```
-True
-```
-## 1- Given an existing post title, retrieve the most similar posts (nearest neighbor search using embeddings)
+
+ True
+
+
+
+## 1- Given an existing post title, retrieve the most similar posts (nearest neighbor search using embeddings)
We can query neighbors of a specific post using `get_nns_by_item`.
-```python PYTHON
+
+```python
+# Choose an example (we'll retrieve others similar to it)
example_id = 50
+# Retrieve nearest neighbors
similar_item_ids = search_index.get_nns_by_item(example_id,
10, # Number of results to retrieve
include_distances=True)
+# Format and print the text and distances
results = pd.DataFrame(data={'post titles': df.iloc[similar_item_ids[0]]['title'],
'distance': similar_item_ids[1]}).drop(example_id)
@@ -299,174 +339,213 @@ print(f"Query post:'{df.iloc[example_id]['title']}'\nNearest neighbors:")
results
```
-```
-Query post:'Pick startups for YC to fund'
-Nearest neighbors:
-```
+ Query post:'Pick startups for YC to fund'
+ Nearest neighbors:
+
+
+
+
-
-
-
- |
- post titles |
- distance |
-
-
-
-
- 2991 |
- Best Bank for Startups? |
- 0.883494 |
-
-
- 2910 |
- Who's looking for a cofounder? |
- 0.885087 |
-
-
- 31 |
- What startup/technology is on your 'to watch' list? |
- 0.887212 |
-
-
- 685 |
- What startup/technology is on your 'to watch' list? |
- 0.887212 |
-
-
- 2123 |
- Who is seeking a cofounder? |
- 0.889451 |
-
-
- 727 |
- Agriculture startups doing interesting work? |
- 0.899192 |
-
-
- 2972 |
- How should I evaluate a startup as I job hunt? |
- 0.901621 |
-
-
- 2589 |
-
- What methods do you use to gain early customers for your startup?
- |
- 0.903065 |
-
-
- 2708 |
- Is there VC appetite for defense related startups? |
- 0.904016 |
-
-
-
+
+
+
+
+ |
+ post titles |
+ distance |
+
+
+
+
+ 2991 |
+ Best Bank for Startups? |
+ 0.883494 |
+
+
+ 2910 |
+ Who's looking for a cofounder? |
+ 0.885087 |
+
+
+ 31 |
+ What startup/technology is on your 'to watch' list? |
+ 0.887212 |
+
+
+ 685 |
+ What startup/technology is on your 'to watch' list? |
+ 0.887212 |
+
+
+ 2123 |
+ Who is seeking a cofounder? |
+ 0.889451 |
+
+
+ 727 |
+ Agriculture startups doing interesting work? |
+ 0.899192 |
+
+
+ 2972 |
+ How should I evaluate a startup as I job hunt? |
+ 0.901621 |
+
+
+ 2589 |
+ What methods do you use to gain early customers for your startup? |
+ 0.903065 |
+
+
+ 2708 |
+ Is there VC appetite for defense related startups? |
+ 0.904016 |
+
+
+
-## 2- Given a query that we write, retrieve the most similar posts
+
+## 2- Given a query that we write, retrieve the most similar posts
We're not limited to searching using existing items. If we get a query, we can embed it and find its nearest neighbors from the dataset.
-```python PYTHON
+
+```python
query = "How can I improve my knowledge of calculus?"
+# Get the query's embedding
+# We'll need to embed the query using the same model that we used to embed the post titles
+# so the query and titles are using the same embedding space.
query_embed = co.embed(texts=[query],
model="embed-english-v3.0",
truncate="RIGHT",
input_type="search_query").embeddings
+# Retrieve the nearest neighbors
similar_item_ids = search_index.get_nns_by_vector(query_embed[0], 10, include_distances=True)
+# Format & print the results
results = pd.DataFrame(data={'texts': df.iloc[similar_item_ids[0]]['title'],
'distance': similar_item_ids[1]})
print(f"Query:'{query}'\nNearest neighbors:")
results
```
-```
-Query:'How can I improve my knowledge of calculus?'
-Nearest neighbors:
-```
+ Query:'How can I improve my knowledge of calculus?'
+ Nearest neighbors:
+
+
+
+
-
-
-
- |
- texts |
- distance |
-
-
-
-
- 2457 |
- How do I improve my command of mathematical language? |
- 0.931286 |
-
-
- 1235 |
- How to learn new things better? |
- 1.024635 |
-
-
- 145 |
- How to self-learn math? |
- 1.044135 |
-
-
- 1317 |
- How can I learn to read mathematical notation? |
- 1.050976 |
-
-
- 910 |
- How Do You Learn? |
- 1.061253 |
-
-
- 2432 |
- How did you learn math notation? |
- 1.070800 |
-
-
- 1994 |
- How do I become smarter? |
- 1.083434 |
-
-
- 1529 |
- How do you personally learn? |
- 1.086088 |
-
-
- 796 |
- How do you keep improving? |
- 1.087251 |
-
-
- 1286 |
- How do I learn drawing? |
- 1.088468 |
-
-
-
+
+
+
+
+ |
+ texts |
+ distance |
+
+
+
+
+ 2457 |
+ How do I improve my command of mathematical language? |
+ 0.931286 |
+
+
+ 1235 |
+ How to learn new things better? |
+ 1.024635 |
+
+
+ 145 |
+ How to self-learn math? |
+ 1.044135 |
+
+
+ 1317 |
+ How can I learn to read mathematical notation? |
+ 1.050976 |
+
+
+ 910 |
+ How Do You Learn? |
+ 1.061253 |
+
+
+ 2432 |
+ How did you learn math notation? |
+ 1.070800 |
+
+
+ 1994 |
+ How do I become smarter? |
+ 1.083434 |
+
+
+ 1529 |
+ How do you personally learn? |
+ 1.086088 |
+
+
+ 796 |
+ How do you keep improving? |
+ 1.087251 |
+
+
+ 1286 |
+ How do I learn drawing? |
+ 1.088468 |
+
+
+
-## 3- Plot the archive of articles by similarity
+
+## 3- Plot the archive of articles by similarity
What if we want to browse the archive instead of only searching it? Let's plot all the questions in a 2D chart so you're able to visualize the posts in the archive and their similarities.
-```python PYTHON
+
+```python
reducer = umap.UMAP(n_neighbors=100)
umap_embeds = reducer.fit_transform(embeds)
```
-```python PYTHON
+
+```python
df['x'] = umap_embeds[:,0]
df['y'] = umap_embeds[:,1]
+# Plot
chart = alt.Chart(df).mark_circle(size=60).encode(
x=#'x',
alt.X('x',
@@ -489,22 +568,44 @@ chart = alt.Chart(df).mark_circle(size=60).encode(
chart.interactive()
```
+
+
+
+
+
-## 4- Cluster the posts to identify the major common themes
+
+
+## 4- Cluster the posts to identify the major common themes
Let's proceed to cluster the embeddings using KMeans from scikit-learn.
-```python PYTHON
+
+```python
+# Pick the number of clusters
n_clusters = 8
+# Cluster the embeddings
kmeans_model = KMeans(n_clusters=n_clusters, random_state=0)
classes = kmeans_model.fit_predict(embeds)
```
## 5- Extract major keywords from each cluster so we can identify what the cluster is about
-```python PYTHON
+
+```python
+# Extract the keywords for each cluster
documents = df['title']
documents = pd.DataFrame({"Document": documents,
"ID": range(len(documents)),
@@ -516,7 +617,8 @@ count = count_vectorizer.transform(documents_per_topic.Document)
words = count_vectorizer.get_feature_names_out()
```
-```python PYTHON
+
+```python
ctfidf = ClassTfidfTransformer().fit_transform(count).toarray()
words_per_class = {label: [words[index] for index in ctfidf[label].argsort()[-10:]] for label in documents_per_topic.Topic}
df['cluster'] = classes
@@ -524,10 +626,10 @@ df['keywords'] = df['cluster'].map(lambda topic_num: ", ".join(np.array(words_pe
```
## Plot with clusters and keywords information
-
We can now plot the documents with their clusters and keywords
-```python PYTHON
+
+```python
selection = alt.selection_multi(fields=['keywords'], bind='legend')
chart = alt.Chart(df).transform_calculate(
@@ -562,10 +664,27 @@ chart = alt.Chart(df).transform_calculate(
chart.interactive()
```
+
+
+
+
+
-## 6- (Experimental) Naming clusters with a generative language model
+
+
+## 6- (Experimental) Naming clusters with a generative language model
While the extracted keywords do add a lot of information to help us identify the clusters at a glance, we should be able to have a generative model look at these keywords and suggest a name. So far I have reasonable results from a prompt that looks like this:
```
@@ -582,11 +701,9 @@ The common theme of the following words:
is that they all relate to
```
-There's a lot of room for improvement though. I'm really excited by this use case because it adds so much information. Imagine if the in the following tree of topics, you assigned each cluster an intelligible name. Then imagine if you assigned each _branching_ a name as well
+There's a lot of room for improvement though. I'm really excited by this use case because it adds so much information. Imagine if the in the following tree of topics, you assigned each cluster an intelligible name. Then imagine if you assigned each *branching* a name as well
-
+
We can’t wait to see what you start building! Share your projects or find support on our [Discord server](https://discord.com/invite/co-mmunity).
+
diff --git a/fern/pages/cookbooks/article-recommender-with-text-embeddings.mdx b/fern/pages/cookbooks/article-recommender-with-text-embeddings.mdx
index 29aa591c5..9507e35ac 100644
--- a/fern/pages/cookbooks/article-recommender-with-text-embeddings.mdx
+++ b/fern/pages/cookbooks/article-recommender-with-text-embeddings.mdx
@@ -1,32 +1,37 @@
---
-title: Article Recommender with Text Embedding and Classification
+title: Article Recommender with Text Embedding Classification Extraction
slug: /page/article-recommender-with-text-embeddings
description: "This page describes how to build a generative-AI tool to recommend articles with Cohere."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI assistant, recommendation engines"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
+
+
+
## Article Recommender with Text Embedding, Classification, and Extraction
-This is a simple demonstration of how we can stack multiple NLP models together
+This is a simple demonstration of how we can stack multiple NLP models together
to get an output much closer to our desired outcome.
-Embeddings can capture the meaning of a piece of text beyond keyword-matching. In this article, we will build a simple news article recommender system that computes the embeddings of all available articles and recommend the most relevant articles based on embeddings similarity.
+Embeddings can capture the meaning of a piece of text beyond keyword-matching. In this article, we will build a simple news article recommender system that computes the embeddings of all available articles and recommend the most relevant articles based on embeddings similarity.
-We will also make the recommendation tighter by using text classification to recommend only articles within the same category. We will then extract a list of tags from each recommended article, which can further help readers discover new articles.
+We will also make the recommendation tighter by using text classification to recommend only articles within the same category. We will then extract a list of tags from each recommended article, which can further help readers discover new articles.
All this will be done via three Cohere API endpoints stacked together: Embed, Classify, and Chat.
-
+
+
+
We will implement the following steps:
@@ -38,25 +43,26 @@ We will implement the following steps:
**4: Show the top 5 recommended articles.**
-```python PYTHON
+
+```python
! pip install cohere
```
-```txt title="Output"
-Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
-Collecting cohere
- Downloading cohere-1.3.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.0 MB)
-[K |████████████████████████████████| 18.0 MB 135 kB/s
-[?25hRequirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from cohere) (2.23.0)
-Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (1.24.3)
-Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (2022.6.15)
-Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (2.10)
-Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (3.0.4)
-Installing collected packages: cohere
-Successfully installed cohere-1.3.10
-```
+ Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
+ Collecting cohere
+ Downloading cohere-1.3.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.0 MB)
+ [K |████████████████████████████████| 18.0 MB 135 kB/s
+ [?25hRequirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from cohere) (2.23.0)
+ Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (1.24.3)
+ Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (2022.6.15)
+ Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (2.10)
+ Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->cohere) (3.0.4)
+ Installing collected packages: cohere
+ Successfully installed cohere-1.3.10
-```python PYTHON
+
+
+```python
import numpy as np
import pandas as pd
import re
@@ -66,70 +72,96 @@ co = cohere.Client("COHERE_API_KEY") # Get your API key: https://dashboard.coher
```
-
+
+
## 1.1: Get articles
-Throughout this article, we'll use the [BBC news article dataset](https://www.kaggle.com/competitions/learn-ai-bbc/data?select=BBC+News+Train.csv) as an example [\[Source\]](http://mlg.ucd.ie/datasets/bbc.html). This dataset consists of articles from a few categories: business, politics, tech, entertainment, and sport.
+Throughout this article, we'll use the [BBC news article dataset](https://www.kaggle.com/competitions/learn-ai-bbc/data?select=BBC+News+Train.csv) as an example [[Source]](http://mlg.ucd.ie/datasets/bbc.html). This dataset consists of articles from a few categories: business, politics, tech, entertainment, and sport.
We'll extract a subset of the data and in Step 1, use the first 100 data points.
-```python PYTHON
+
+
+
+```python
+# Load the dataset to a dataframe
df = pd.read_csv('https://raw.githubusercontent.com/cohere-ai/cohere-developer-experience/main/notebooks/data/bbc_news_subset.csv', delimiter=',')
+# Select a portion of the dataset
INP_START = 0
INP_END = 100
df_inputs = df.iloc[INP_START:INP_END]
df_inputs = df_inputs.copy()
+# Remove columns we don't need
df_inputs.drop(['ArticleId','Category'],axis=1,inplace=True)
+# View the data
df_inputs.head()
```
+
+
+
-
-
-
- |
- Text |
-
-
-
-
- 0 |
- worldcom ex-boss launches defence lawyers defe... |
-
-
- 1 |
- german business confidence slides german busin... |
-
-
- 2 |
- bbc poll indicates economic gloom citizens in ... |
-
-
- 3 |
- lifestyle governs mobile choice faster bett... |
-
-
- 4 |
- enron bosses in $168m payout eighteen former e... |
-
-
-
+
+
+
+
+ |
+ Text |
+
+
+
+
+ 0 |
+ worldcom ex-boss launches defence lawyers defe... |
+
+
+ 1 |
+ german business confidence slides german busin... |
+
+
+ 2 |
+ bbc poll indicates economic gloom citizens in ... |
+
+
+ 3 |
+ lifestyle governs mobile choice faster bett... |
+
+
+ 4 |
+ enron bosses in $168m payout eighteen former e... |
+
+
+
+
+
## 1.2: Turn articles into embeddings
+
Next we turn each article text into embeddings. An [embedding](https://docs.cohere.ai/embedding-wiki) is a list of numbers that our models use to represent a piece of text, capturing its context and meaning.
We do this by calling Cohere's [Embed endpoint](https://docs.cohere.ai/embed-reference), which takes in text as input and returns embeddings as output.
-```python PYTHON
+
+```python
+# Get text embeddings via the Embed endpoint
articles = df_inputs['Text'].tolist()
output = co.embed(
@@ -141,31 +173,36 @@ embeds = output.embeddings
print('Number of articles:', len(embeds))
```
-```
-Number of articles: 100
-```
+ Number of articles: 100
+
## 1.3: Pick one article and find the most similar articles
Next, we pick any one article to be the one the reader is currently reading (let's call this the target) and find other articles with the most similar embeddings (let's call these candidates) using cosine similarity.
-[Cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity) is a metric that measures how similar sequences of numbers are (embeddings in our case), and we compute it for each target-candidate pair.
+[Cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity) is a metric that measures how similar sequences of numbers are (embeddings in our case), and we compute it for each target-candidate pair.
+
-```python PYTHON
+```python
+# Choose one article ID as the one you are currently reading
print(f'Choose one article ID between {INP_START} and {INP_END-1} below...')
```
-```
-Choose one article ID between 0 and 99 below...
-```
+ Choose one article ID between 0 and 99 below...
+
+
-```python PYTHON
+```python
+# Enter your article ID
READING_IDX = 70
+# Get embedding for the article
reading = embeds[READING_IDX]
```
-```python PYTHON
+
+```python
+# Calculate cosine similarity between the target and candidate articles
from sklearn.metrics.pairwise import cosine_similarity
@@ -186,9 +223,12 @@ def get_similarity(target,candidates):
return similarity_scores
```
-```python PYTHON
+
+```python
+# Get the similarity between the target and candidate articles
similarity = get_similarity(reading,embeds)
+# View the top 5 articles
print('Target:')
print(f'[ID {READING_IDX}]',df_inputs['Text'][READING_IDX][:100],'...','\n')
@@ -197,88 +237,113 @@ for i in similarity[1:6]: # Exclude the target article
print(f'[ID {i[0]}]',df_inputs['Text'][i[0]][:100],'...')
```
-```
-Target:
-[ID 70] aragones angered by racism fine spain coach luis aragones is furious after being fined by the spanis ...
-
-Candidates:
-[ID 23] ferguson urges henry punishment sir alex ferguson has called on the football association to punish a ...
-[ID 51] mourinho defiant on chelsea form chelsea boss jose mourinho has insisted that sir alex ferguson and ...
-[ID 73] balco case trial date pushed back the trial date for the bay area laboratory cooperative (balco) ste ...
-[ID 41] mcleish ready for criticism rangers manager alex mcleish accepts he is going to be criticised after ...
-[ID 42] premier league planning cole date the premier league is attempting to find a mutually convenient dat ...
-```
+ Target:
+ [ID 70] aragones angered by racism fine spain coach luis aragones is furious after being fined by the spanis ...
+
+ Candidates:
+ [ID 23] ferguson urges henry punishment sir alex ferguson has called on the football association to punish a ...
+ [ID 51] mourinho defiant on chelsea form chelsea boss jose mourinho has insisted that sir alex ferguson and ...
+ [ID 73] balco case trial date pushed back the trial date for the bay area laboratory cooperative (balco) ste ...
+ [ID 41] mcleish ready for criticism rangers manager alex mcleish accepts he is going to be criticised after ...
+ [ID 42] premier league planning cole date the premier league is attempting to find a mutually convenient dat ...
+
+
+# **2: Keep only articles of the same category using text classification**
-
+
Two articles may be similar but they may not necessarily belong to the same category. For example, an article about a sports team manager facing a fine may be similar to another about a business entity facing a fine, but they are not of the same category.
Perhaps we can make the system better by only recommending articles of the same category. For this, let's build a news category classifier.
+
+
## 2.1: Build a classifier
-We use Cohere's [Classify endpoint](https://docs.cohere.com/reference/classify) to build a news category classifier, classifying articles into five categories: Business, Politics, Tech, Entertainment, and Sport.
+
+We use Cohere's [Classify endpoint](https://docs.cohere.ai/classify-reference) to build a news category classifier, classifying articles into five categories: Business, Politics, Tech, Entertainment, and Sport.
A typical text classification model requires hundreds/thousands of data points to train, but with this endpoint, we can build a classifier with a few as five examples per class.
To build the classifier, we need a set of examples consisting of text (news text) and labels (news category). The BBC News dataset happens to have both (columns 'Text' and 'Category'), so this time we’ll use the categories for building our examples. For this, we will set aside another portion of dataset.
-```python PYTHON
+
+```python
+# Select a portion of the dataset to sample the classification examples from
EX_START = 100
EX_END = 200
df_examples = df.iloc[EX_START:EX_END]
df_examples = df_examples.copy()
+# Remove columns we don't need
df_examples.drop(['ArticleId'],axis=1,inplace=True)
+# View the data
df_examples.head()
```
+
+
+
-
-
-
- |
- Text |
- Category |
-
-
-
-
- 100 |
- honda wins china copyright ruling japan s hond... |
- business |
-
-
- 101 |
- ukip could sue veritas defectors the uk indepe... |
- politics |
-
-
- 102 |
- security warning over fbi virus the us feder... |
- tech |
-
-
- 103 |
- europe backs digital tv lifestyle how people r... |
- tech |
-
-
- 104 |
- celebrities get to stay in jungle all four con... |
- entertainment |
-
-
-
+
+
+
+
+ |
+ Text |
+ Category |
+
+
+
+
+ 100 |
+ honda wins china copyright ruling japan s hond... |
+ business |
+
+
+ 101 |
+ ukip could sue veritas defectors the uk indepe... |
+ politics |
+
+
+ 102 |
+ security warning over fbi virus the us feder... |
+ tech |
+
+
+ 103 |
+ europe backs digital tv lifestyle how people r... |
+ tech |
+
+
+ 104 |
+ celebrities get to stay in jungle all four con... |
+ entertainment |
+
+
+
+
+
With the Classify endpoint, there is a limit of 512 tokens per input. This means full articles won't be able to fit in the examples, so we will approximate and limit each article to its first 300 characters.
-```python PYTHON
+
+```python
+# Shorten the example articles (because the medium endpoint max token limit is 2048)
MAX_CHARS = 300
def shorten_text(text):
@@ -289,11 +354,15 @@ df_examples['Text'] = df_examples['Text'].apply(shorten_text)
The Classify endpoint needs a minimum of 2 examples for each category. We'll have 5 examples each, sampled randomly from the dataset. We have 5 categories, so we will have a total of 25 examples.
-```python PYTHON
-EX_PER_CAT = 5
+```python
+# Set the number of examples per category
+EX_PER_CAT = 5
+
+# Get the list of all available categories
categories = df_examples['Category'].unique().tolist()
+# Create list of examples containing texts and labels
ex_texts = []
ex_labels = []
for category in categories:
@@ -308,23 +377,26 @@ print(f'Number of categories: {len(categories)}')
print(f'Total number of examples: {len(ex_texts)}')
```
-```
-Number of examples per category: 5
-List of categories: ['business', 'politics', 'tech', 'entertainment', 'sport']
-Number of categories: 5
-Total number of examples: 25
-```
+ Number of examples per category: 5
+ List of categories: ['business', 'politics', 'tech', 'entertainment', 'sport']
+ Number of categories: 5
+ Total number of examples: 25
+
Once the examples are ready, we can now get the classifications. Here is a function that returns the classification given an input.
-```python PYTHON
+
+```python
+# Get classifications via the Classify endpoint
from cohere import ClassifyExample
+# Collate the examples
examples = []
for txt, lbl in zip(ex_texts,ex_labels):
examples.append(ClassifyExample(text=txt, label=lbl))
+# Classification function
def classify_text(texts, examples):
classifications = co.classify(
inputs=texts,
@@ -338,97 +410,126 @@ def classify_text(texts, examples):
Before actually using the classifier, let's first test its performance. Here we take another 100 data points as the test dataset and the classifier will predict its class i.e. news category.
-```python PYTHON
+
+```python
+# Select a portion of the dataset for testing the classifier
TEST_START = 200
TEST_END = 300
df_test = df.iloc[TEST_START:TEST_END]
df_test = df_test.copy()
+# Remove columns we don't need
df_test.drop(['ArticleId'],axis=1,inplace=True)
+# Shorten the text to fit token limit
df_test['Text'] = df_test['Text'].apply(shorten_text)
+# View the data
df_test.head()
```
+
+
+
-
-
-
- |
- Text |
- Category |
-
-
-
-
- 200 |
- sa return to mauritius top seeds south africa ... |
- sport |
-
-
- 201 |
- snow patrol feted at irish awards snow patrol ... |
- entertainment |
-
-
- 202 |
- clyde 0-5 celtic celtic brushed aside clyde to... |
- sport |
-
-
- 203 |
- bad weather hits nestle sales a combination of... |
- business |
-
-
- 204 |
- net fingerprints combat attacks eighty large n... |
- tech |
-
-
-
+
+
+
+
+ |
+ Text |
+ Category |
+
+
+
+
+ 200 |
+ sa return to mauritius top seeds south africa ... |
+ sport |
+
+
+ 201 |
+ snow patrol feted at irish awards snow patrol ... |
+ entertainment |
+
+
+ 202 |
+ clyde 0-5 celtic celtic brushed aside clyde to... |
+ sport |
+
+
+ 203 |
+ bad weather hits nestle sales a combination of... |
+ business |
+
+
+ 204 |
+ net fingerprints combat attacks eighty large n... |
+ tech |
+
+
+
-```python PYTHON
+
+
+
+```python
+# Create batches of texts and classify them
predictions = []
BATCH_SIZE = 90 # The API accepts a maximum of 96 inputs
for i in range(0, len(df_test['Text']), BATCH_SIZE):
batch_texts = df_test['Text'][i:i+BATCH_SIZE].tolist()
- predictions.extend(classify_text(batch_texts, examples))
-
+ predictions.extend(classify_text(batch_texts, examples))
+
+# Actual classes
actual = df_test['Category'].tolist()
```
-```python PYTHON
+
+```python
+# Compute metrics on the test dataset
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(actual, predictions)
print(f'Accuracy: {accuracy*100}')
```
-```
-Accuracy: 89.0
-```
+ Accuracy: 89.0
+
-We get a good accuracy score of 91%, so the classifier is ready to be
+We get a good accuracy score of 91%, so the classifier is ready to be
implemented in our recommender system.
-
+# **3: Extract tags from these articles.**
-We now proceed to the tags extraction step. Compared to the previous two steps, this step is not about sorting or filtering articles, but rather enriching them with more information.
+
+
+We now proceed to the tags extraction step. Compared to the previous two steps, this step is not about sorting or filtering articles, but rather enriching them with more information.
We do this with the Chat endpoint.
We call the endpoint by specifying a few settings, and it will generate the corresponding extractions.
-```python PYTHON
+
+```python
+# Get extractions via the Generate endpoint
def extract_tags(article):
prompt = f"""Given an article, extract a list of tags containing keywords of that article.
+# Examples
Article: japanese banking battle at an end japan s sumitomo mitsui \
financial has withdrawn its takeover offer for rival bank ufj holdings enabling the \
latter to merge with mitsubishi tokyo. sumitomo bosses told counterparts at ufj of its \
@@ -454,8 +555,8 @@ Tags: apple, apple powerbook 100, laptop
Article:{article}
Tags:"""
-
-
+
+
response = co.chat(
model='command-r',
message=prompt,
@@ -464,39 +565,48 @@ Tags:"""
return response.text
```
-
+# **4: Show the top 5 recommended articles.**
+
+
Let's now put everything together for our article recommender system.
First, we select the target article and compute the similarity scores against the candidate articles.
-```python PYTHON
+
+```python
+# Choose one article ID as the one you are currently reading
print(f'Choose one article ID between {INP_START} and {INP_END-1} below...')
```
-```
-Choose one article ID between 0 and 99 below...
-```
+ Choose one article ID between 0 and 99 below...
+
-```python PYTHON
+
+```python
+# Enter your article ID
READING_IDX = 70
+# Get embedding for the article
reading = embeds[READING_IDX]
+# Get the similarity between the target and candidate articles
similarity = get_similarity(reading,embeds)
```
Next, we filter the articles via classification. Finally, we extract the keywords from each article and show the recommendations.
-```python PYTHON
+
+
+```python
+# Choose the number of articles to recommend
SHOW_TOP = 5
+# Shorten the text to fit token limit
df_inputs = df_inputs.copy()
df_inputs['Text'] = df_inputs['Text'].apply(shorten_text)
+# Get the recommendations
def get_recommendations(reading_idx,similarity,show_top):
# Show the current article
@@ -515,7 +625,7 @@ def get_recommendations(reading_idx,similarity,show_top):
# Classify each candidate article
candidate_class = classify_text([df_inputs['Text'][idx]],examples)
-
+
# Show recommendations
if target_class == candidate_class and idx != reading_idx:
selection = df_inputs['Text'][idx][:MAX_CHARS]
@@ -526,7 +636,7 @@ def get_recommendations(reading_idx,similarity,show_top):
if tags:
print(f'Tags: {tags.strip()}\n')
else:
- print(f'Tags: none\n')
+ print(f'Tags: none\n')
# Increment the article count
count += 1
@@ -536,109 +646,122 @@ def get_recommendations(reading_idx,similarity,show_top):
break
```
-```python PYTHON
-get_recommendations(READING_IDX,similarity,SHOW_TOP)
-```
+```python
+# Show the recommended articles
+get_recommendations(READING_IDX,similarity,SHOW_TOP)
```
------- You are reading... ------
-[ID 70] Article: aragones angered by racism fine spain coach luis aragones is furious after being fined by the spanish football federation for his comments about thierry henry. the 66-year-old criticised his 3000 euros (£2 060) punishment even though it was far below the maximum penalty. i am not guilty nor do i ...
------- You might also like... ------
-[ID 23] Article: ferguson urges henry punishment sir alex ferguson has called on the football association to punish arsenal s thierry henry for an incident involving gabriel heinze. ferguson believes henry deliberately caught heinze on the head with his knee during united s controversial win. the united boss said i...
-Tags: football, sir alex ferguson, thierry henry, arsenal, manchester united
+ ------ You are reading... ------
+ [ID 70] Article: aragones angered by racism fine spain coach luis aragones is furious after being fined by the spanish football federation for his comments about thierry henry. the 66-year-old criticised his 3000 euros (£2 060) punishment even though it was far below the maximum penalty. i am not guilty nor do i ...
+
+ ------ You might also like... ------
+ [ID 23] Article: ferguson urges henry punishment sir alex ferguson has called on the football association to punish arsenal s thierry henry for an incident involving gabriel heinze. ferguson believes henry deliberately caught heinze on the head with his knee during united s controversial win. the united boss said i...
+ Tags: football, sir alex ferguson, thierry henry, arsenal, manchester united
+
+ [ID 51] Article: mourinho defiant on chelsea form chelsea boss jose mourinho has insisted that sir alex ferguson and arsene wenger would swap places with him. mourinho s side were knocked out of the fa cup by newcastle last sunday before seeing barcelona secure a 2-1 champions league first-leg lead in the nou camp....
+ Tags: chelsea, jose mourinho, sir alex ferguson, arsene wenger, fa cup, newcastle, barcelona, champions league
+
+ [ID 41] Article: mcleish ready for criticism rangers manager alex mcleish accepts he is going to be criticised after their disastrous uefa cup exit at the hands of auxerre at ibrox on wednesday. mcleish told bbc radio five live: we were in pole position to get through to the next stage but we blew it we absolutel...
+ Tags: rangers, alex mcleish, auxerre, uefa cup, ibrox
+
+ [ID 42] Article: premier league planning cole date the premier league is attempting to find a mutually convenient date to investigate allegations chelsea made an illegal approach for ashley cole. both chelsea and arsenal will be asked to give evidence to a premier league commission but no deadline has been put on ...
+ Tags: premier league, chelsea, arsenal, ashley cole
+
+ [ID 14] Article: ireland 21-19 argentina an injury-time dropped goal by ronan o gara stole victory for ireland from underneath the noses of argentina at lansdowne road on saturday. o gara kicked all of ireland s points with two dropped goals and five penalties to give the home side a 100% record in their autumn i...
+ Tags: rugby, ireland, argentina, ronan o gara
+
-[ID 51] Article: mourinho defiant on chelsea form chelsea boss jose mourinho has insisted that sir alex ferguson and arsene wenger would swap places with him. mourinho s side were knocked out of the fa cup by newcastle last sunday before seeing barcelona secure a 2-1 champions league first-leg lead in the nou camp....
-Tags: chelsea, jose mourinho, sir alex ferguson, arsene wenger, fa cup, newcastle, barcelona, champions league
-[ID 41] Article: mcleish ready for criticism rangers manager alex mcleish accepts he is going to be criticised after their disastrous uefa cup exit at the hands of auxerre at ibrox on wednesday. mcleish told bbc radio five live: we were in pole position to get through to the next stage but we blew it we absolutel...
-Tags: rangers, alex mcleish, auxerre, uefa cup, ibrox
+Keeping to the Section 1.3 example, here we see how the classification and extraction steps have improved our recommendation outcome.
-[ID 42] Article: premier league planning cole date the premier league is attempting to find a mutually convenient date to investigate allegations chelsea made an illegal approach for ashley cole. both chelsea and arsenal will be asked to give evidence to a premier league commission but no deadline has been put on ...
-Tags: premier league, chelsea, arsenal, ashley cole
+First, now the article with ID 73 (non sport) doesn't get recommended anymore. And now we have the tags related to each article being generated.
-[ID 14] Article: ireland 21-19 argentina an injury-time dropped goal by ronan o gara stole victory for ireland from underneath the noses of argentina at lansdowne road on saturday. o gara kicked all of ireland s points with two dropped goals and five penalties to give the home side a 100% record in their autumn i...
-Tags: rugby, ireland, argentina, ronan o gara
-```
-Keeping to the Section 1.3 example, here we see how the classification and extraction steps have improved our recommendation outcome.
-First, now the article with ID 73 (non sport) doesn't get recommended anymore. And now we have the tags related to each article being generated.
Let's try a couple of other articles in business and tech and see the output...
Business article (returning recommendations around German economy and economic growth/slump):
-```python PYTHON
+```python
+# A business news article example (ID 40)
+
+# Enter your article ID
READING_IDX = 1
+# Get embedding for the article
reading = embeds[READING_IDX]
+# Get the similarity between the target and candidate articles
similarity = get_similarity(reading,embeds)
+# Show the recommended articles
get_recommendations(READING_IDX,similarity,SHOW_TOP)
```
-```
------- You are reading... ------
-[ID 1] Article: german business confidence slides german business confidence fell in february knocking hopes of a speedy recovery in europe s largest economy. munich-based research institute ifo said that its confidence index fell to 95.5 in february from 97.5 in january its first decline in three months. the stu...
-
------- You might also like... ------
-[ID 56] Article: borussia dortmund near bust german football club and former european champion borussia dortmund has warned it will go bankrupt if rescue talks with creditors fail. the company s shares tumbled after it said it has entered a life-threatening profitability and financial situation . borussia dortmund...
-Tags: borussia dortmund, german football, bankruptcy
-
-[ID 2] Article: bbc poll indicates economic gloom citizens in a majority of nations surveyed in a bbc world service poll believe the world economy is worsening. most respondents also said their national economy was getting worse. but when asked about their own family s financial outlook a majority in 14 countries...
-Tags: bbc, economy, financial outlook
-
-[ID 8] Article: car giant hit by mercedes slump a slump in profitability at luxury car maker mercedes has prompted a big drop in profits at parent daimlerchrysler. the german-us carmaker saw fourth quarter operating profits fall to 785m euros ($1bn) from 2.4bn euros in 2003. mercedes-benz s woes - its profits slid...
-Tags: daimlerchrysler, mercedes, luxury car, profitability
+ ------ You are reading... ------
+ [ID 1] Article: german business confidence slides german business confidence fell in february knocking hopes of a speedy recovery in europe s largest economy. munich-based research institute ifo said that its confidence index fell to 95.5 in february from 97.5 in january its first decline in three months. the stu...
+
+ ------ You might also like... ------
+ [ID 56] Article: borussia dortmund near bust german football club and former european champion borussia dortmund has warned it will go bankrupt if rescue talks with creditors fail. the company s shares tumbled after it said it has entered a life-threatening profitability and financial situation . borussia dortmund...
+ Tags: borussia dortmund, german football, bankruptcy
+
+ [ID 2] Article: bbc poll indicates economic gloom citizens in a majority of nations surveyed in a bbc world service poll believe the world economy is worsening. most respondents also said their national economy was getting worse. but when asked about their own family s financial outlook a majority in 14 countries...
+ Tags: bbc, economy, financial outlook
+
+ [ID 8] Article: car giant hit by mercedes slump a slump in profitability at luxury car maker mercedes has prompted a big drop in profits at parent daimlerchrysler. the german-us carmaker saw fourth quarter operating profits fall to 785m euros ($1bn) from 2.4bn euros in 2003. mercedes-benz s woes - its profits slid...
+ Tags: daimlerchrysler, mercedes, luxury car, profitability
+
+ [ID 32] Article: china continues rapid growth china s economy has expanded by a breakneck 9.5% during 2004 faster than predicted and well above 2003 s 9.1%. the news may mean more limits on investment and lending as beijing tries to take the economy off the boil. china has sucked in raw materials and energy to fee...
+ Tags: china, economy, beijing
+
+ [ID 96] Article: bmw to recall faulty diesel cars bmw is to recall all cars equipped with a faulty diesel fuel-injection pump supplied by parts maker robert bosch. the faulty part does not represent a safety risk and the recall only affects pumps made in december and january. bmw said that it was too early to say h...
+ Tags: bmw, diesel cars, robert bosch, fuel injection pump
+
-[ID 32] Article: china continues rapid growth china s economy has expanded by a breakneck 9.5% during 2004 faster than predicted and well above 2003 s 9.1%. the news may mean more limits on investment and lending as beijing tries to take the economy off the boil. china has sucked in raw materials and energy to fee...
-Tags: china, economy, beijing
-
-[ID 96] Article: bmw to recall faulty diesel cars bmw is to recall all cars equipped with a faulty diesel fuel-injection pump supplied by parts maker robert bosch. the faulty part does not represent a safety risk and the recall only affects pumps made in december and january. bmw said that it was too early to say h...
-Tags: bmw, diesel cars, robert bosch, fuel injection pump
-```
Tech article (returning recommendations around consumer devices):
-```python PYTHON
+```python
+# A tech news article example (ID 30)
+
+# Enter your article ID
READING_IDX = 71
+# Get embedding for the article
reading = embeds[READING_IDX]
+# Get the similarity between the target and candidate articles
similarity = get_similarity(reading,embeds)
+# Show the recommended articles
get_recommendations(READING_IDX,similarity,SHOW_TOP)
```
-```txt title="Output"
------- You are reading... ------
-[ID 71] Article: camera phones are must-haves four times more mobiles with cameras in them will be sold in europe by the end of 2004 than last year says a report from analysts gartner. globally the number sold will reach 159 million an increase of 104%. the report predicts that nearly 70% of all mobile phones ...
-
------- You might also like... ------
-[ID 3] Article: lifestyle governs mobile choice faster better or funkier hardware alone is not going to help phone firms sell more handsets research suggests. instead phone firms keen to get more out of their customers should not just be pushing the technology for its own sake. consumers are far more interest...
-Tags: mobile, lifestyle, phone firms, handsets
-
-[ID 69] Article: gates opens biggest gadget fair bill gates has opened the consumer electronics show (ces) in las vegas saying that gadgets are working together more to help people manage multimedia content around the home and on the move. mr gates made no announcement about the next generation xbox games console ...
-Tags: bill gates, consumer electronics show, gadgets, xbox
-
-[ID 46] Article: china ripe for media explosion asia is set to drive global media growth to 2008 and beyond with china and india filling the two top spots analysts have predicted. japan south korea and singapore will also be strong players but china s demographics give it the edge a media conference in londo...
-Tags: china, india, japan, south korea, singapore, global media growth
+ ------ You are reading... ------
+ [ID 71] Article: camera phones are must-haves four times more mobiles with cameras in them will be sold in europe by the end of 2004 than last year says a report from analysts gartner. globally the number sold will reach 159 million an increase of 104%. the report predicts that nearly 70% of all mobile phones ...
+
+ ------ You might also like... ------
+ [ID 3] Article: lifestyle governs mobile choice faster better or funkier hardware alone is not going to help phone firms sell more handsets research suggests. instead phone firms keen to get more out of their customers should not just be pushing the technology for its own sake. consumers are far more interest...
+ Tags: mobile, lifestyle, phone firms, handsets
+
+ [ID 69] Article: gates opens biggest gadget fair bill gates has opened the consumer electronics show (ces) in las vegas saying that gadgets are working together more to help people manage multimedia content around the home and on the move. mr gates made no announcement about the next generation xbox games console ...
+ Tags: bill gates, consumer electronics show, gadgets, xbox
+
+ [ID 46] Article: china ripe for media explosion asia is set to drive global media growth to 2008 and beyond with china and india filling the two top spots analysts have predicted. japan south korea and singapore will also be strong players but china s demographics give it the edge a media conference in londo...
+ Tags: china, india, japan, south korea, singapore, global media growth
+
+ [ID 19] Article: moving mobile improves golf swing a mobile phone that recognises and responds to movements has been launched in japan. the motion-sensitive phone - officially titled the v603sh - was developed by sharp and launched by vodafone s japanese division. devised mainly for mobile gaming users can also ac...
+ Tags: mobile phone, japan, sharp, vodafone, golf swing
+
+ [ID 63] Article: what high-definition will do to dvds first it was the humble home video then it was the dvd and now hollywood is preparing for the next revolution in home entertainment - high-definition. high-definition gives incredible 3d-like pictures and surround sound. the dvd disks and the gear to play the...
+ Tags: high-definition, dvd, hollywood, home entertainment
+
-[ID 19] Article: moving mobile improves golf swing a mobile phone that recognises and responds to movements has been launched in japan. the motion-sensitive phone - officially titled the v603sh - was developed by sharp and launched by vodafone s japanese division. devised mainly for mobile gaming users can also ac...
-Tags: mobile phone, japan, sharp, vodafone, golf swing
-
-[ID 63] Article: what high-definition will do to dvds first it was the humble home video then it was the dvd and now hollywood is preparing for the next revolution in home entertainment - high-definition. high-definition gives incredible 3d-like pictures and surround sound. the dvd disks and the gear to play the...
-Tags: high-definition, dvd, hollywood, home entertainment
-```
In conclusion, this demonstrates an example of how we can stack multiple NLP endpoints together to get an output much closer to our desired outcome.
In practice, hosting and maintaining multiple models can turn quickly into a complex activity. But by leveraging Cohere endpoints, this task is reduced to a simple API call.
-
-```
-
-```
diff --git a/fern/pages/cookbooks/basic-multi-step.mdx b/fern/pages/cookbooks/basic-multi-step.mdx
index 2f45b1bfb..739a2c12b 100644
--- a/fern/pages/cookbooks/basic-multi-step.mdx
+++ b/fern/pages/cookbooks/basic-multi-step.mdx
@@ -1,16 +1,19 @@
---
-title: Multi-Step Tool Use with Cohere
+title: Multi-Step Tool Use
slug: /page/basic-multi-step
description: "This page describes how to create a multi-step, tool-using AI agent with Cohere's tool use functionality."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI assistant, agent, LLMs, agent tool use"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
Tool use allows developers to connect Cohere's models to external tools like search engines, APIs, functions, databases, etc.
@@ -20,30 +23,31 @@ The recommended way to achieve [multi-step tool use with Cohere](https://docs.co
## Install Dependencies
-```python PYTHON
-! pip install --quiet langchain langchain_cohere langchain_experimental
-```
-```txt title="Output"
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m812.8/812.8 kB[0m [31m6.5 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m194.1/194.1 kB[0m [31m4.7 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.9/1.9 MB[0m [31m9.6 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m276.8/276.8 kB[0m [31m7.7 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m87.5/87.5 kB[0m [31m3.7 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m145.9/145.9 kB[0m [31m2.8 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m21.7 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m75.6/75.6 kB[0m [31m7.1 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m49.4/49.4 kB[0m [31m4.1 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m53.0/53.0 kB[0m [31m4.8 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m144.8/144.8 kB[0m [31m4.9 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m77.9/77.9 kB[0m [31m1.9 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m58.3/58.3 kB[0m [31m5.5 MB/s[0m eta [36m0:00:00[0m
-[?25h
+```python
+! pip install --quiet langchain langchain_cohere langchain_experimental
```
-```python PYTHON
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m812.8/812.8 kB[0m [31m6.5 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m194.1/194.1 kB[0m [31m4.7 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.9/1.9 MB[0m [31m9.6 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m276.8/276.8 kB[0m [31m7.7 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m87.5/87.5 kB[0m [31m3.7 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m145.9/145.9 kB[0m [31m2.8 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m21.7 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m75.6/75.6 kB[0m [31m7.1 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m49.4/49.4 kB[0m [31m4.1 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m53.0/53.0 kB[0m [31m4.8 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m144.8/144.8 kB[0m [31m4.9 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m77.9/77.9 kB[0m [31m1.9 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m58.3/58.3 kB[0m [31m5.5 MB/s[0m eta [36m0:00:00[0m
+ [?25h
+
+
+```python
+# LLM
import os
-os.environ['COHERE_API_KEY'] =
+os.environ['COHERE_API_KEY'] = ""
```
## Define tools
@@ -58,10 +62,10 @@ Your agent will be equipped with the following tools. The model can pick between
Plus the model can self-reflect.
#### Web search
-
You can easily equip your agent with web search!
-```python PYTHON
+
+```python
from langchain_community.tools.tavily_search import TavilySearchResults
os.environ["TAVILY_API_KEY"] = # you can create an API key for free on Tavily's website
@@ -78,39 +82,43 @@ internet_search.args_schema = TavilySearchInput
```
#### Vector store
-
You can easily equip your agent with a vector store!
-```python PYTHON
+
+```python
!pip --quiet install faiss-cpu tiktoken
```
-```txt title="Output"
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m27.0/27.0 MB[0m [31m41.4 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.8/1.8 MB[0m [31m58.3 MB/s[0m eta [36m0:00:00[0m
-[?25h
-```
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m27.0/27.0 MB[0m [31m41.4 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.8/1.8 MB[0m [31m58.3 MB/s[0m eta [36m0:00:00[0m
+ [?25h
-```python PYTHON
+
+```python
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_cohere import CohereEmbeddings
+# Set embeddings
embd = CohereEmbeddings()
+# Docs to index
urls = [
"https://paulgraham.com/best.html",
]
+# Load
docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]
+# Split
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=512, chunk_overlap=0
)
doc_splits = text_splitter.split_documents(docs_list)
+# Add to vectorstore
vectorstore = FAISS.from_documents(
documents=doc_splits,
embedding=embd,
@@ -120,7 +128,8 @@ vectorstore_retriever = vectorstore.as_retriever()
```
-```python PYTHON
+
+```python
from langchain.tools.retriever import create_retriever_tool
vectorstore_search = create_retriever_tool(
@@ -131,10 +140,10 @@ vectorstore_search = create_retriever_tool(
```
#### Python interpreter tool
-
You can easily equip your agent with a python interpreter!
-```python PYTHON
+
+```python
from langchain.agents import Tool
from langchain_experimental.utilities import PythonREPL
@@ -146,16 +155,22 @@ python_tool = Tool(
)
python_tool.name = "python_interpreter"
+# from langchain_core.pydantic_v1 import BaseModel, Field
class ToolInput(BaseModel):
code: str = Field(description="Python code to execute.")
python_tool.args_schema = ToolInput
```
-#### Transform any Python function in a Tool
+```python
+
+```
+
+#### Transform any Python function in a Tool
You can easily equip your agent with any Python function!
-```python PYTHON
+
+```python
from langchain_core.tools import tool
import random
@@ -180,25 +195,30 @@ random_operation_tool.args_schema = random_operation_inputs
## Create ReAct Agent
-The model can smartly pick the right tool(s) for the user query, call them in any sequence, analyze the results and self-reflect.
+The model can smartly pick the right tool(s) for the user query, call them in any sequence, analyze the results and self-reflect.
Once the model considers it has enough information to answer the user question, it generates the final answer.
-```python PYTHON
+
+```python
from langchain.agents import AgentExecutor
from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_cohere.chat_models import ChatCohere
+# LLM
llm = ChatCohere(model="command-r-plus", temperature=0.3)
+# Preamble
preamble = """
You are an expert who answers the user's question with the most relevant datasource. You are equipped with an internet search tool and a special vectorstore of information about how to write good essays.
You also have a 'random_operation_tool' tool, you must use it to compute the random operation between two numbers.
"""
+# Prompt template
prompt = ChatPromptTemplate.from_template("{input}")
+# Create the ReAct agent
agent = create_cohere_react_agent(
llm=llm,
tools=[internet_search, vectorstore_search, python_tool, random_operation_tool],
@@ -208,11 +228,16 @@ agent = create_cohere_react_agent(
agent_executor = AgentExecutor(agent=agent, tools=[internet_search, vectorstore_search, python_tool, random_operation_tool], verbose=True)
```
-## Ask a standalone question to the ReAct agent
+```python
+
+```
+
+## Ask a standalone question to the ReAct agent
A question that requires using a predefined tool from Langchain
-```python PYTHON
+
+```python
response = agent_executor.invoke({
"input": "I want to write an essay about the Roman Empire. Any tips for writing an essay? Any fun facts?",
"preamble": preamble,
@@ -220,188 +245,197 @@ response = agent_executor.invoke({
response['output']
+# note that the model smartly looks in the vector db, and then online
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will search for tips on writing an essay and fun facts about the Roman Empire.
-{'tool_name': 'vectorstore_search', 'parameters': {'query': 'tips for writing an essay'}}
-[0m[33;1m[1;3mbe? I should have asked how do you write essays well? Though
-these seem only phrasing apart, their answers diverge. The answer
-to the first question, as we've seen, isn't really about essay
-writing. The second question forces it to be.Writing essays, at its best, is a way of discovering ideas. How do
-you do that well? How do you discover by writing?An essay should ordinarily start with what I'm going to call a
-question, though I mean this in a very general sense: it doesn't
-have to be a question grammatically, just something that acts like
-one in the sense that it spurs some response.How do you get this initial question? It probably won't work to
-choose some important-sounding topic at random and go at it.
-Professional traders won't even trade unless they have what they
-call an edge — a convincing story about why in some class of
-trades they'll win more than they lose. Similarly, you shouldn't
-attack a topic unless you have a way in — some new insight about
-it or way of approaching it.You don't need to have a complete thesis; you just need some kind
-of gap you can explore. In fact, merely having questions about
-something other people take for granted can be edge enough.If you come across a question that's sufficiently puzzling, it could
-be worth exploring even if it doesn't seem very momentous. Many an
-important discovery has been made by pulling on a thread that seemed
-insignificant at first. How can they all be finches?
-[2]Once you've got a question, then what? You start thinking out loud
-about it. Not literally out loud, but you commit to a specific
-string of words in response, as you would if you were talking. This
-initial response is usually mistaken or incomplete. Writing converts
-your ideas from vague to bad. But that's a step forward, because
-once you can see the brokenness, you can fix it.Perhaps beginning writers are alarmed at the thought of starting
-with something mistaken or incomplete, but you shouldn't be, because
-this is why essay writing works. Forcing yourself to commit to some
-specific string of words gives you a starting point, and if it's
-wrong, you'll see that when you reread it. At least half of essay
-writing is rereading what you've written and asking is this correct
-
-didn't have edge with any of them. To start writing an essay, you
-need a topic plus some initial insight about it, and you can't
-generate those systematically. If only.
-[9]You can probably cause yourself to have more of them, though. The
-quality of the ideas that come out of your head depends on what goes
-in, and you can improve that in two dimensions, breadth and depth.You can't learn everything, so getting breadth implies learning
-about topics that are very different from one another. When I tell
-people about my book-buying trips to Hay and they ask what I buy
-books about, I usually feel a bit sheepish answering, because the
-topics seem like a laundry list of unrelated subjects. But perhaps
-that's actually optimal in this business.You can also get ideas by talking to people, by doing and building
-things, and by going places and seeing things. I don't think it's
-important to talk to new people so much as the sort of people who
-make you have new ideas. I get more new ideas after talking for an
-afternoon with Robert Morris than from talking to 20 new smart
-people. I know because that's what a block of office hours at Y
-Combinator consists of.While breadth comes from reading and talking and seeing, depth comes
-from doing. The way to really learn about some domain is to have
-to solve problems in it. Though this could take the form of writing,
-I suspect that to be a good essayist you also have to do, or have
-done, some other kind of work. That may not be true for most other
-fields, but essay writing is different. You could spend half your
-time working on something else and be net ahead, so long as it was
-hard.I'm not proposing that as a recipe so much as an encouragement to
-those already doing it. If you've spent all your life so far working
-on other things, you're already halfway there. Though of course to
-be good at writing you have to like it, and if you like writing
-you'd probably have spent at least some time doing it.Everything I've said about initial questions applies also to the
-questions you encounter in writing the essay. They're the same
-thing; every subtree of an essay is usually a shorter essay, just
-as every subtree of a Calder mobile is a smaller mobile. So any
-
-You don't have to get an answer right the first time, but there's
-no excuse for not getting it right eventually, because you can keep
-rewriting till you do. And this is not just a theoretical possibility.
-It's a pretty accurate description of the way I work. I'm rewriting
-as we speak.But although I wish I could say that writing great essays depends mostly
-on effort, in the limit case it's inspiration that makes the
-difference. In the limit case, the questions are the harder thing
-to get. That pool has no bottom.How to get more questions? That is the most important question of
-all.Notes[1]
-There might be some resistance to this conclusion on the
-grounds that some of these discoveries could only be understood by
-a small number of readers. But you get into all sorts of difficulties
-if you want to disqualify essays on this account. How do you decide
-where the cutoff should be? If a virus kills off everyone except a
-handful of people sequestered at Los Alamos,
-could an essay that had been disqualified now be eligible? Etc.Darwin's 1844 essay was derived from an earlier version written in 1839.
-Extracts from it were published in 1858.[2]
-When you find yourself very curious about an apparently minor
-question, that's an exciting sign. Evolution has designed you to
-pay attention to things that matter. So when you're very curious
-about something random, that could mean you've unconsciously noticed
-it's less random than it seems.[3]
-Corollary: If you're not intellectually honest, your writing
-won't just be biased, but also boring, because you'll miss all the
-ideas you'd have discovered if you pushed for the truth.[4]
-Sometimes this process begins before you start writing.
-Sometimes you've already figured out the first few things you want
-to say. Schoolchildren are often taught they should decide everything
-they want to say, and write this down as an outline before they
-start writing the essay itself. Maybe that's a good way to get them
-started — or not, I don't know — but it's antithetical to the
-spirit of essay writing. The more detailed your outline, the less
-your ideas can benefit from the sort of discovery that essays are for.[5]
-The problem with this type of "greedy" algorithm is that you
-
-technique that gets you good initial questions also gets you good
-whole essays.At some point the cycle of question and response reaches what feels
-like a natural end. Which is a little suspicious; shouldn't every
-answer suggest more questions? I think what happens is that you
-start to feel sated. Once you've covered enough interesting ground,
-you start to lose your appetite for new questions. Which is just
-as well, because the reader is probably feeling sated too. And it's
-not lazy to stop asking questions, because you could instead be
-asking the initial question of a new essay.That's the ultimate source of drag on the connectedness of ideas:
-the discoveries you make along the way. If you discover enough
-starting from question A, you'll never make it to question B. Though
-if you keep writing essays you'll gradually fix this problem by
-burning off such discoveries. So bizarrely enough, writing lots of
-essays makes it as if the space of ideas were more highly connected.When a subtree comes to an end, you can do one of two things. You
-can either stop, or pull the Cubist trick of laying separate subtrees
-end to end by returning to a question you skipped earlier. Usually
-it requires some sleight of hand to make the essay flow continuously
-at this point, but not this time. This time I actually need an
-example of the phenomenon. For example, we discovered earlier that
-the best possible essay wouldn't usually be timeless in the way the
-best painting would. This seems surprising enough to be
-worth investigating further.There are two senses in which an essay can be timeless: to be about
-a matter of permanent importance, and always to have the same effect
-on readers. With art these two senses blend together. Art that
-looked beautiful to the ancient Greeks still looks beautiful to us.
-But with essays the two senses diverge, because essays
-teach, and you can't teach people something they already know.
-Natural selection is certainly a matter of permanent importance,
-but an essay explaining it couldn't have the same effect on us that
-it would have had on Darwin's contemporaries, precisely because his
-ideas were so successful that everyone already knows about them.
-[10]I imagined when I started writing this that the best possible essay
-would be timeless in the stricter, evergreen sense: that it would[0m[32;1m[1;3m
-{'tool_name': 'internet_search', 'parameters': {'query': 'fun facts about the roman empire'}}
-[0m[36;1m[1;3m[{'url': 'https://www.natgeokids.com/uk/discover/history/romans/10-facts-about-the-ancient-romans/', 'content': 'i love this website\nBIG BOBBY\nbooby\nI love shell my bae;)\ni like bobby fishes ;0\nI like turtles\nOmg soy cool\ngreeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatttttttttttttttttttttttt\nbest fact ever\nthis artical is cool\nHANDY\nrubbish did not help what so ever\nha\nRocking\nTHIS IS THE BEST\nproper rad in it cool\nthis is cool\nawesomeness\nawsome\nawsome\nthank you captain\nit is a lot of help\ni like this\nwebsite it helps me on my projects and isabel likes munier\nmark uses this for research\nlot of help\nthis is awsome\nTHE BEST BOOBOO\nCool webpage helped me get 4 housepoints\n This helped me A LOT on a school project\ncool wow awesomoe\nCOOL WEBSITE LOL\nthis helped me with a school project :)\nthat was awesome\ncool\nthat helped me out for my research test\nReally its very cool really COOL\nLIKE COOL best website so far its nice\nI love it\nnice facts\nIt help with my history\n i mean u made animaljam a awesome nice safe place for kids and this site to have kids a safe website to get facts for reports and stuff\nLots of Love ,\nRose\npretty good website if u ask me\nbut definently not gonna use it on a daily basis\nIll try it again another time\ngood\nCool webcite\nterrible\nquite impressive\nAwesome website it real helps\nits good\nthis is a great website! You really a lot with my project!:)\nthis has helleped\nme get\nmy progect\ndone\nthank you\nsoooooooooooooooooo\nmuchchchchchch\nthis helleped me\nsooooooooo much with my progect thank you\nvery good website\nthank us very much your nice one today!!\n'}, {'url': 'https://ohfact.com/roman-empire-facts/', 'content': 'Learn about the ancient Roman Civilization, its history, culture, army, architecture, food and more from this list of 27 facts. Discover how the Romans started, conquered, lived, died and influenced the world with their legends, myths and facts.'}, {'url': 'https://factnight.com/fun-facts-about-the-roman-empire/', 'content': 'The Roman Empire was one of the most influential and significant civilizations in world history. At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people. From its legendary beginnings and remarkable achievements to its eventual decline and fall, the Roman Empire is a fascinating topic full of little-known facts and intriguing trivia.'}, {'url': 'https://www.historyhit.com/facts-about-ancient-rome-and-the-romans/', 'content': 'The Enduring Legacy of C.S. Lewis\nMargaret J. Winkler: A Forgotten Pioneer in Disney’s Success\n10 Facts About Harper Lee\nAntarctica Expedition Cruise\nUncover Pompeii\nSophie Hay and Tristan Hughes\nRediscovering Richard III with Matt Lewis\nOrder the History Hit Miscellany\nHistory Hit Holidays\nGift Subscriptions\n100 Facts About Ancient Rome and the Romans\nRome wasn’t built in a day, as the cliché reminds us. The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire\nBarbarian factions, tribes and war leaders were now a factor in the power struggles at the top of Roman politics and one of the once-strong boundaries of the Empire had proved to be permeable.\n Related Articles\n10 Facts About Saint Andrew\nThe Rise of Pompey the Great, the ‘Roman Alexander’\nWatch and Listen\nCleopatra\nSex in Ancient Rome\nRelated Locations\nBaelo Claudia\nMausoleum of Cecilia Metella\nColin Ricketts\n30 July 2021\n By the fourth century BC, the story was accepted by Romans who were proud of their warrior founder\nThe story was included in the first history of the city, by the Greek writer Diocles of Peparethus, and the twins and their wolf step-mother were depicted on Rome’s first coins.\n The History Hit Miscellany of Facts, Figures and Fascinating Finds\nA History of England: Part One\nDragons: Myth & Reality\nA Tudor Wonder - Hardwick Hall\nThe Battle of Shrewsbury\nEurope’s 1848 Revolutions\nThe Boston Tea Party\nHow Did 3 People Seemingly Escape From Alcatraz?\n'}, {'url': 'https://www.countryfaq.com/facts-about-the-roman-empire/', 'content': 'Facts about the Roman Empire. Explore some of the interesting, fun, cool facts bout the Roman Empire: 1. The Magnificent Roman Empire. The Roman Empire, a colossal entity of unparalleled grandeur, occupies an indomitable position within the annals of human history, a name that resonates resoundingly across the eons.'}][0m[32;1m[1;3mRelevant Documents: 0,3,4,5
-Cited Documents: 0,3,4,5
-Answer: Here are some tips for writing an essay:
-- Start with a question that spurs some response.
-- Don't choose a topic at random, make sure you have a way in, a new insight or approach.
-- You don't need a complete thesis, just a gap to explore.
-- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.
-- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.
-- You can get breadth by reading and talking about a wide range of topics.
-- You can get depth by doing and having to solve problems.
-- You can also get ideas by talking to people who make you have new ideas.
-
-Here are some fun facts about the Roman Empire:
-- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.
-- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.
-- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.
-Grounded answer: Here are some tips for writing an essay:
-- Start with a question that spurs some response.
-- Don't choose a topic at random, make sure you have a way in, a new insight or approach.
-- You don't need a complete thesis, just a gap to explore.
-- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.
-- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.
-- You can get breadth by reading and talking about a wide range of topics.
-- You can get depth by doing and having to solve problems.
-- You can also get ideas by talking to people who make you have new ideas.
-
-Here are some fun facts about the Roman Empire:
-- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.
-- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.
-- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.[0m
-
-[1m> Finished chain.[0m
-
-
-
-
-
-"Here are some tips for writing an essay:\n- Start with a question that spurs some response.\n- Don't choose a topic at random, make sure you have a way in, a new insight or approach.\n- You don't need a complete thesis, just a gap to explore.\n- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.\n- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.\n- You can get breadth by reading and talking about a wide range of topics.\n- You can get depth by doing and having to solve problems.\n- You can also get ideas by talking to people who make you have new ideas.\n\nHere are some fun facts about the Roman Empire:\n- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.\n- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.\n- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire."
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for tips on writing an essay and fun facts about the Roman Empire.
+ {'tool_name': 'vectorstore_search', 'parameters': {'query': 'tips for writing an essay'}}
+ [0m[33;1m[1;3mbe? I should have asked how do you write essays well? Though
+ these seem only phrasing apart, their answers diverge. The answer
+ to the first question, as we've seen, isn't really about essay
+ writing. The second question forces it to be.Writing essays, at its best, is a way of discovering ideas. How do
+ you do that well? How do you discover by writing?An essay should ordinarily start with what I'm going to call a
+ question, though I mean this in a very general sense: it doesn't
+ have to be a question grammatically, just something that acts like
+ one in the sense that it spurs some response.How do you get this initial question? It probably won't work to
+ choose some important-sounding topic at random and go at it.
+ Professional traders won't even trade unless they have what they
+ call an edge — a convincing story about why in some class of
+ trades they'll win more than they lose. Similarly, you shouldn't
+ attack a topic unless you have a way in — some new insight about
+ it or way of approaching it.You don't need to have a complete thesis; you just need some kind
+ of gap you can explore. In fact, merely having questions about
+ something other people take for granted can be edge enough.If you come across a question that's sufficiently puzzling, it could
+ be worth exploring even if it doesn't seem very momentous. Many an
+ important discovery has been made by pulling on a thread that seemed
+ insignificant at first. How can they all be finches?
+ [2]Once you've got a question, then what? You start thinking out loud
+ about it. Not literally out loud, but you commit to a specific
+ string of words in response, as you would if you were talking. This
+ initial response is usually mistaken or incomplete. Writing converts
+ your ideas from vague to bad. But that's a step forward, because
+ once you can see the brokenness, you can fix it.Perhaps beginning writers are alarmed at the thought of starting
+ with something mistaken or incomplete, but you shouldn't be, because
+ this is why essay writing works. Forcing yourself to commit to some
+ specific string of words gives you a starting point, and if it's
+ wrong, you'll see that when you reread it. At least half of essay
+ writing is rereading what you've written and asking is this correct
+
+ didn't have edge with any of them. To start writing an essay, you
+ need a topic plus some initial insight about it, and you can't
+ generate those systematically. If only.
+ [9]You can probably cause yourself to have more of them, though. The
+ quality of the ideas that come out of your head depends on what goes
+ in, and you can improve that in two dimensions, breadth and depth.You can't learn everything, so getting breadth implies learning
+ about topics that are very different from one another. When I tell
+ people about my book-buying trips to Hay and they ask what I buy
+ books about, I usually feel a bit sheepish answering, because the
+ topics seem like a laundry list of unrelated subjects. But perhaps
+ that's actually optimal in this business.You can also get ideas by talking to people, by doing and building
+ things, and by going places and seeing things. I don't think it's
+ important to talk to new people so much as the sort of people who
+ make you have new ideas. I get more new ideas after talking for an
+ afternoon with Robert Morris than from talking to 20 new smart
+ people. I know because that's what a block of office hours at Y
+ Combinator consists of.While breadth comes from reading and talking and seeing, depth comes
+ from doing. The way to really learn about some domain is to have
+ to solve problems in it. Though this could take the form of writing,
+ I suspect that to be a good essayist you also have to do, or have
+ done, some other kind of work. That may not be true for most other
+ fields, but essay writing is different. You could spend half your
+ time working on something else and be net ahead, so long as it was
+ hard.I'm not proposing that as a recipe so much as an encouragement to
+ those already doing it. If you've spent all your life so far working
+ on other things, you're already halfway there. Though of course to
+ be good at writing you have to like it, and if you like writing
+ you'd probably have spent at least some time doing it.Everything I've said about initial questions applies also to the
+ questions you encounter in writing the essay. They're the same
+ thing; every subtree of an essay is usually a shorter essay, just
+ as every subtree of a Calder mobile is a smaller mobile. So any
+
+ You don't have to get an answer right the first time, but there's
+ no excuse for not getting it right eventually, because you can keep
+ rewriting till you do. And this is not just a theoretical possibility.
+ It's a pretty accurate description of the way I work. I'm rewriting
+ as we speak.But although I wish I could say that writing great essays depends mostly
+ on effort, in the limit case it's inspiration that makes the
+ difference. In the limit case, the questions are the harder thing
+ to get. That pool has no bottom.How to get more questions? That is the most important question of
+ all.Notes[1]
+ There might be some resistance to this conclusion on the
+ grounds that some of these discoveries could only be understood by
+ a small number of readers. But you get into all sorts of difficulties
+ if you want to disqualify essays on this account. How do you decide
+ where the cutoff should be? If a virus kills off everyone except a
+ handful of people sequestered at Los Alamos,
+ could an essay that had been disqualified now be eligible? Etc.Darwin's 1844 essay was derived from an earlier version written in 1839.
+ Extracts from it were published in 1858.[2]
+ When you find yourself very curious about an apparently minor
+ question, that's an exciting sign. Evolution has designed you to
+ pay attention to things that matter. So when you're very curious
+ about something random, that could mean you've unconsciously noticed
+ it's less random than it seems.[3]
+ Corollary: If you're not intellectually honest, your writing
+ won't just be biased, but also boring, because you'll miss all the
+ ideas you'd have discovered if you pushed for the truth.[4]
+ Sometimes this process begins before you start writing.
+ Sometimes you've already figured out the first few things you want
+ to say. Schoolchildren are often taught they should decide everything
+ they want to say, and write this down as an outline before they
+ start writing the essay itself. Maybe that's a good way to get them
+ started — or not, I don't know — but it's antithetical to the
+ spirit of essay writing. The more detailed your outline, the less
+ your ideas can benefit from the sort of discovery that essays are for.[5]
+ The problem with this type of "greedy" algorithm is that you
+
+ technique that gets you good initial questions also gets you good
+ whole essays.At some point the cycle of question and response reaches what feels
+ like a natural end. Which is a little suspicious; shouldn't every
+ answer suggest more questions? I think what happens is that you
+ start to feel sated. Once you've covered enough interesting ground,
+ you start to lose your appetite for new questions. Which is just
+ as well, because the reader is probably feeling sated too. And it's
+ not lazy to stop asking questions, because you could instead be
+ asking the initial question of a new essay.That's the ultimate source of drag on the connectedness of ideas:
+ the discoveries you make along the way. If you discover enough
+ starting from question A, you'll never make it to question B. Though
+ if you keep writing essays you'll gradually fix this problem by
+ burning off such discoveries. So bizarrely enough, writing lots of
+ essays makes it as if the space of ideas were more highly connected.When a subtree comes to an end, you can do one of two things. You
+ can either stop, or pull the Cubist trick of laying separate subtrees
+ end to end by returning to a question you skipped earlier. Usually
+ it requires some sleight of hand to make the essay flow continuously
+ at this point, but not this time. This time I actually need an
+ example of the phenomenon. For example, we discovered earlier that
+ the best possible essay wouldn't usually be timeless in the way the
+ best painting would. This seems surprising enough to be
+ worth investigating further.There are two senses in which an essay can be timeless: to be about
+ a matter of permanent importance, and always to have the same effect
+ on readers. With art these two senses blend together. Art that
+ looked beautiful to the ancient Greeks still looks beautiful to us.
+ But with essays the two senses diverge, because essays
+ teach, and you can't teach people something they already know.
+ Natural selection is certainly a matter of permanent importance,
+ but an essay explaining it couldn't have the same effect on us that
+ it would have had on Darwin's contemporaries, precisely because his
+ ideas were so successful that everyone already knows about them.
+ [10]I imagined when I started writing this that the best possible essay
+ would be timeless in the stricter, evergreen sense: that it would[0m[32;1m[1;3m
+ {'tool_name': 'internet_search', 'parameters': {'query': 'fun facts about the roman empire'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.natgeokids.com/uk/discover/history/romans/10-facts-about-the-ancient-romans/', 'content': 'i love this website\nBIG BOBBY\nbooby\nI love shell my bae;)\ni like bobby fishes ;0\nI like turtles\nOmg soy cool\ngreeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatttttttttttttttttttttttt\nbest fact ever\nthis artical is cool\nHANDY\nrubbish did not help what so ever\nha\nRocking\nTHIS IS THE BEST\nproper rad in it cool\nthis is cool\nawesomeness\nawsome\nawsome\nthank you captain\nit is a lot of help\ni like this\nwebsite it helps me on my projects and isabel likes munier\nmark uses this for research\nlot of help\nthis is awsome\nTHE BEST BOOBOO\nCool webpage helped me get 4 housepoints\n This helped me A LOT on a school project\ncool wow awesomoe\nCOOL WEBSITE LOL\nthis helped me with a school project :)\nthat was awesome\ncool\nthat helped me out for my research test\nReally its very cool really COOL\nLIKE COOL best website so far its nice\nI love it\nnice facts\nIt help with my history\n i mean u made animaljam a awesome nice safe place for kids and this site to have kids a safe website to get facts for reports and stuff\nLots of Love ,\nRose\npretty good website if u ask me\nbut definently not gonna use it on a daily basis\nIll try it again another time\ngood\nCool webcite\nterrible\nquite impressive\nAwesome website it real helps\nits good\nthis is a great website! You really a lot with my project!:)\nthis has helleped\nme get\nmy progect\ndone\nthank you\nsoooooooooooooooooo\nmuchchchchchch\nthis helleped me\nsooooooooo much with my progect thank you\nvery good website\nthank us very much your nice one today!!\n'}, {'url': 'https://ohfact.com/roman-empire-facts/', 'content': 'Learn about the ancient Roman Civilization, its history, culture, army, architecture, food and more from this list of 27 facts. Discover how the Romans started, conquered, lived, died and influenced the world with their legends, myths and facts.'}, {'url': 'https://factnight.com/fun-facts-about-the-roman-empire/', 'content': 'The Roman Empire was one of the most influential and significant civilizations in world history. At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people. From its legendary beginnings and remarkable achievements to its eventual decline and fall, the Roman Empire is a fascinating topic full of little-known facts and intriguing trivia.'}, {'url': 'https://www.historyhit.com/facts-about-ancient-rome-and-the-romans/', 'content': 'The Enduring Legacy of C.S. Lewis\nMargaret J. Winkler: A Forgotten Pioneer in Disney’s Success\n10 Facts About Harper Lee\nAntarctica Expedition Cruise\nUncover Pompeii\nSophie Hay and Tristan Hughes\nRediscovering Richard III with Matt Lewis\nOrder the History Hit Miscellany\nHistory Hit Holidays\nGift Subscriptions\n100 Facts About Ancient Rome and the Romans\nRome wasn’t built in a day, as the cliché reminds us. The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire\nBarbarian factions, tribes and war leaders were now a factor in the power struggles at the top of Roman politics and one of the once-strong boundaries of the Empire had proved to be permeable.\n Related Articles\n10 Facts About Saint Andrew\nThe Rise of Pompey the Great, the ‘Roman Alexander’\nWatch and Listen\nCleopatra\nSex in Ancient Rome\nRelated Locations\nBaelo Claudia\nMausoleum of Cecilia Metella\nColin Ricketts\n30 July 2021\n By the fourth century BC, the story was accepted by Romans who were proud of their warrior founder\nThe story was included in the first history of the city, by the Greek writer Diocles of Peparethus, and the twins and their wolf step-mother were depicted on Rome’s first coins.\n The History Hit Miscellany of Facts, Figures and Fascinating Finds\nA History of England: Part One\nDragons: Myth & Reality\nA Tudor Wonder - Hardwick Hall\nThe Battle of Shrewsbury\nEurope’s 1848 Revolutions\nThe Boston Tea Party\nHow Did 3 People Seemingly Escape From Alcatraz?\n'}, {'url': 'https://www.countryfaq.com/facts-about-the-roman-empire/', 'content': 'Facts about the Roman Empire. Explore some of the interesting, fun, cool facts bout the Roman Empire: 1. The Magnificent Roman Empire. The Roman Empire, a colossal entity of unparalleled grandeur, occupies an indomitable position within the annals of human history, a name that resonates resoundingly across the eons.'}][0m[32;1m[1;3mRelevant Documents: 0,3,4,5
+ Cited Documents: 0,3,4,5
+ Answer: Here are some tips for writing an essay:
+ - Start with a question that spurs some response.
+ - Don't choose a topic at random, make sure you have a way in, a new insight or approach.
+ - You don't need a complete thesis, just a gap to explore.
+ - You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.
+ - You can improve the quality of your ideas by increasing the breadth and depth of what goes in.
+ - You can get breadth by reading and talking about a wide range of topics.
+ - You can get depth by doing and having to solve problems.
+ - You can also get ideas by talking to people who make you have new ideas.
+
+ Here are some fun facts about the Roman Empire:
+ - At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.
+ - The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.
+ - The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.
+ Grounded answer: Here are some tips for writing an essay:
+ - Start with a question that spurs some response.
+ - Don't choose a topic at random, make sure you have a way in, a new insight or approach.
+ - You don't need a complete thesis, just a gap to explore.
+ - You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.
+ - You can improve the quality of your ideas by increasing the breadth and depth of what goes in.
+ - You can get breadth by reading and talking about a wide range of topics.
+ - You can get depth by doing and having to solve problems.
+ - You can also get ideas by talking to people who make you have new ideas.
+
+ Here are some fun facts about the Roman Empire:
+ - At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.
+ - The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.
+ - The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ "Here are some tips for writing an essay:\n- Start with a question that spurs some response.\n- Don't choose a topic at random, make sure you have a way in, a new insight or approach.\n- You don't need a complete thesis, just a gap to explore.\n- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.\n- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.\n- You can get breadth by reading and talking about a wide range of topics.\n- You can get depth by doing and having to solve problems.\n- You can also get ideas by talking to people who make you have new ideas.\n\nHere are some fun facts about the Roman Empire:\n- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.\n- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.\n- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire."
+
+
+
+
+```python
+
```
A question that requires the large language model to use a custom tool.
-```python PYTHON
+
+```python
response = agent_executor.invoke({
"input": "Calculate the result of the random operation of 10 and 20. Then find a few fun facts about that number, as well as its prime factors.",
"preamble": preamble,
@@ -409,49 +443,58 @@ response = agent_executor.invoke({
response['output']
+# note that the model uses a sequence of tools
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-First, I will calculate the result of the random operation between 10 and 20. Then, I will search for fun facts about that number and its prime factors.
-{'tool_name': 'random_operation_tool', 'parameters': {'a': 10, 'b': 20}}
-[0mrandom_operation_tool is not a valid tool, try one of [internet_search, vectorstore_search, python_interpreter, random_operation].[32;1m[1;3m
-I received an error message when trying to use the random_operation_tool. I will now try using the python_interpreter tool to calculate the random operation between 10 and 20.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import random\n\n# Define the two numbers\na = 10\nb = 20\n\n# Calculate the random operation\nresult = random.choice(['+', '-', '*', '/'])\n\n# Perform the operation\nif result == '+':\n answer = a + b\nelif result == '-':\n answer = a - b\nelif result == '*':\n answer = a * b\nelif result == '/':\n answer = a / b\n\nprint(f'The result of the random operation is {answer:.0f}')"}}
-[0m[38;5;200m[1;3mThe result of the random operation is 200
-[0m[32;1m[1;3m
-The result of the random operation is 200. Now I will search for fun facts about the number 200 and its prime factors.
-{'tool_name': 'internet_search', 'parameters': {'query': 'fun facts about the number 200'}}
-[0m[36;1m[1;3m[{'url': 'https://www.express.co.uk/life-style/top10facts/690340/Top-10-facts-number-200', 'content': "Top 10 facts about the number 200 TODAY is the 200th day of 2016, so to celebrate let's have some facts about the number 200. By WILLIAM HARTSTON. 00:01, Mon, Jul 18, 2016."}, {'url': 'https://en.wikipedia.org/wiki/200_(number)', 'content': "The number appears in the Padovan sequence, preceded by 86, 114, 151 (it is the sum of the first two of these). The sum of Euler's totient function φ(x) over the first twenty-five integers is 200. 200 is the smallest base 10 unprimeable number - it cannot be turned into a prime number by changing just one of its digits to any other digit."}, {'url': 'https://www.archimedes-lab.org/numbers/Num70_200.html', 'content': "With 189 pages filled with an incredible variety of fun facts on numbers (and their peculiar properties), both mathematical and cultural, as well as tantalizing problems and anecdotes, there is much to learn for everyone. ... The number 200, according to Bullinger's study of biblical literature, signifies 'insufficiency'. The word 200 (ducenti) ..."}, {'url': 'https://owlcation.com/misc/Over-200-Odd-Facts-Did-You-Know-Them', 'content': "Over 200 odd facts about science, sports, history and more that you and your friends probably don't already know! ... Strange and Interesting Facts. ... Average number of people airborne over the U.S. at any given hour: 61,000. Portion of land in the U.S. owned by the government: 1/3. Ninety percent of New York City cabbies are recently arrived ..."}, {'url': 'https://numbermatics.com/n/200/', 'content': 'Mathematical info, prime factorization, fun facts and numerical data for STEM, education and fun. Your guide to the number 200, an even composite number composed of two distinct primes. Mathematical info, prime factorization, fun facts and numerical data for STEM, education and fun. ... Number 200 - Facts about the integer. Retrieved 2 April ...'}][0m[32;1m[1;3m
-{'tool_name': 'internet_search', 'parameters': {'query': 'prime factors of 200'}}
-[0m[36;1m[1;3m[{'url': 'https://www.cuemath.com/numbers/factors-of-200/', 'content': 'Therefore, the factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, and 200. Which means the number 200 is an even composite number.'}, {'url': 'https://byjus.com/maths/factors-of-200/', 'content': "The factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100 and 200. Visit BYJU'S to learn the pair factors and the prime factors of 200 with complete\xa0..."}, {'url': 'https://byjus.com/us/math/factors-of-200/', 'content': 'The factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100 and 200 because all these numbers divide the number 200 evenly.'}, {'url': 'https://homework.study.com/explanation/what-is-the-prime-factorization-of-200-using-exponents.html', 'content': 'The prime factorization of 200 using exponents is 2 3 ∗ 5 2 . First, we need to find the prime factorization of 200. 200 = 2 ∗ 100. 200 = 2 ∗ 2 ∗ 50.'}][0m[32;1m[1;3mRelevant Documents: 1,3,4,6,7,8,9,10
-Cited Documents: 1,3,4,6,7,8,9,10
-Answer: The result of the random operation is **200**. Here are some fun facts about the number 200:
-- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.
-- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.
-- The number 200 is an even composite number composed of two distinct primes.
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ First, I will calculate the result of the random operation between 10 and 20. Then, I will search for fun facts about that number and its prime factors.
+ {'tool_name': 'random_operation_tool', 'parameters': {'a': 10, 'b': 20}}
+ [0mrandom_operation_tool is not a valid tool, try one of [internet_search, vectorstore_search, python_interpreter, random_operation].[32;1m[1;3m
+ I received an error message when trying to use the random_operation_tool. I will now try using the python_interpreter tool to calculate the random operation between 10 and 20.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import random\n\n# Define the two numbers\na = 10\nb = 20\n\n# Calculate the random operation\nresult = random.choice(['+', '-', '*', '/'])\n\n# Perform the operation\nif result == '+':\n answer = a + b\nelif result == '-':\n answer = a - b\nelif result == '*':\n answer = a * b\nelif result == '/':\n answer = a / b\n\nprint(f'The result of the random operation is {answer:.0f}')"}}
+ [0m[38;5;200m[1;3mThe result of the random operation is 200
+ [0m[32;1m[1;3m
+ The result of the random operation is 200. Now I will search for fun facts about the number 200 and its prime factors.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'fun facts about the number 200'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.express.co.uk/life-style/top10facts/690340/Top-10-facts-number-200', 'content': "Top 10 facts about the number 200 TODAY is the 200th day of 2016, so to celebrate let's have some facts about the number 200. By WILLIAM HARTSTON. 00:01, Mon, Jul 18, 2016."}, {'url': 'https://en.wikipedia.org/wiki/200_(number)', 'content': "The number appears in the Padovan sequence, preceded by 86, 114, 151 (it is the sum of the first two of these). The sum of Euler's totient function φ(x) over the first twenty-five integers is 200. 200 is the smallest base 10 unprimeable number - it cannot be turned into a prime number by changing just one of its digits to any other digit."}, {'url': 'https://www.archimedes-lab.org/numbers/Num70_200.html', 'content': "With 189 pages filled with an incredible variety of fun facts on numbers (and their peculiar properties), both mathematical and cultural, as well as tantalizing problems and anecdotes, there is much to learn for everyone. ... The number 200, according to Bullinger's study of biblical literature, signifies 'insufficiency'. The word 200 (ducenti) ..."}, {'url': 'https://owlcation.com/misc/Over-200-Odd-Facts-Did-You-Know-Them', 'content': "Over 200 odd facts about science, sports, history and more that you and your friends probably don't already know! ... Strange and Interesting Facts. ... Average number of people airborne over the U.S. at any given hour: 61,000. Portion of land in the U.S. owned by the government: 1/3. Ninety percent of New York City cabbies are recently arrived ..."}, {'url': 'https://numbermatics.com/n/200/', 'content': 'Mathematical info, prime factorization, fun facts and numerical data for STEM, education and fun. Your guide to the number 200, an even composite number composed of two distinct primes. Mathematical info, prime factorization, fun facts and numerical data for STEM, education and fun. ... Number 200 - Facts about the integer. Retrieved 2 April ...'}][0m[32;1m[1;3m
+ {'tool_name': 'internet_search', 'parameters': {'query': 'prime factors of 200'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.cuemath.com/numbers/factors-of-200/', 'content': 'Therefore, the factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, and 200. Which means the number 200 is an even composite number.'}, {'url': 'https://byjus.com/maths/factors-of-200/', 'content': "The factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100 and 200. Visit BYJU'S to learn the pair factors and the prime factors of 200 with complete\xa0..."}, {'url': 'https://byjus.com/us/math/factors-of-200/', 'content': 'The factors of 200 are 1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100 and 200 because all these numbers divide the number 200 evenly.'}, {'url': 'https://homework.study.com/explanation/what-is-the-prime-factorization-of-200-using-exponents.html', 'content': 'The prime factorization of 200 using exponents is 2 3 ∗ 5 2 . First, we need to find the prime factorization of 200. 200 = 2 ∗ 100. 200 = 2 ∗ 2 ∗ 50.'}][0m[32;1m[1;3mRelevant Documents: 1,3,4,6,7,8,9,10
+ Cited Documents: 1,3,4,6,7,8,9,10
+ Answer: The result of the random operation is **200**. Here are some fun facts about the number 200:
+ - It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.
+ - According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.
+ - The number 200 is an even composite number composed of two distinct primes.
+
+ The prime factors of 200 are 2 and 5.
+ Grounded answer: The result of the random operation is **200**. Here are some fun facts about the number 200:
+ - It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.
+ - According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.
+ - The number 200 is an even composite number composed of two distinct primes.
+
+ The prime factors of 200 are 2 and 5.[0m
+
+ [1m> Finished chain.[0m
+
+
-The prime factors of 200 are 2 and 5.
-Grounded answer: The result of the random operation is **200**. Here are some fun facts about the number 200:
-- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.
-- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.
-- The number 200 is an even composite number composed of two distinct primes.
-The prime factors of 200 are 2 and 5.[0m
-[1m> Finished chain.[0m
+ "The result of the random operation is **200**. Here are some fun facts about the number 200:\n- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.\n- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.\n- The number 200 is an even composite number composed of two distinct primes.\n\nThe prime factors of 200 are 2 and 5."
+```python
-"The result of the random operation is **200**. Here are some fun facts about the number 200:\n- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.\n- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.\n- The number 200 is an even composite number composed of two distinct primes.\n\nThe prime factors of 200 are 2 and 5."
```
A question that requires the large language model to directly answer.
-```python PYTHON
+
+```python
response = agent_executor.invoke({
"input": "Hey how are you?",
"preamble": preamble,
@@ -459,32 +502,40 @@ response = agent_executor.invoke({
response['output']
+# note that the modle can directly answer!
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will respond to the user's greeting.
-{'tool_name': 'directly_answer', 'parameters': {}}
-[0mdirectly_answer is not a valid tool, try one of [internet_search, vectorstore_search, python_interpreter, random_operation].[32;1m[1;3mRelevant Documents: None
-Cited Documents: None
-Answer: I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?
-Grounded answer: I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will respond to the user's greeting.
+ {'tool_name': 'directly_answer', 'parameters': {}}
+ [0mdirectly_answer is not a valid tool, try one of [internet_search, vectorstore_search, python_interpreter, random_operation].[32;1m[1;3mRelevant Documents: None
+ Cited Documents: None
+ Answer: I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?
+ Grounded answer: I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?[0m
+
+ [1m> Finished chain.[0m
+
+
-[1m> Finished chain.[0m
+ "I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?"
-"I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?"
+
+```python
+
```
## Ask a more complex question to the ReAct agent
-
A question that requires using multipe tools, in sequence
-```python PYTHON
+
+```python
response = agent_executor.invoke({
"input": "In what year was the company that was founded as Sound of Music went public? What was its stock price in 2000 and 2010.",
"preamble": preamble,
@@ -493,35 +544,43 @@ response = agent_executor.invoke({
response['output']
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will search for the company that was founded as Sound of Music. Then, I will search for the year it went public. Finally, I will search for its stock price in 2000 and 2010.
-{'tool_name': 'internet_search', 'parameters': {'query': 'company founded as Sound of Music'}}
-[0m[36;1m[1;3m[{'url': 'https://www.mprnews.org/story/2012/05/15/best-buy-richard-schulze-legacy', 'content': 'Amazon is taking a piece of everyone\'s business,"\nSome analysts have questioned the extent to which Schulze\'s strong hand over the company has held it back in the face of digital competition. "\nSchulze hit on the "Best Buy" strategy when a twister ripped open a store and the company held a huge sale with low prices and lots of promotion. And Richard Schulz was able to outthink and outmaneuver the competition to put up Best Buy as the definitive place in the brick-and-mortar world to buy electronic equipment," Spector said.\n Best Buy\'s Richard Schulze: Stereo seller to retail giant\nShare\nIn 1966, Best Buy was a stereo specialty retailer called Sound of Music, founded by Richard Schulze in St. Paul.\n Former CEO Anderson said it is possible that Schulze\'s goals for the company were out of touch with the digital age, and that Schulze may have stuck around too long.\n'}, {'url': 'https://corporate.bestbuy.com/tag/sound-of-music/', 'content': 'As we celebrate Best Buy’s 50th anniversary, we sat down with founder and Chairman Emeritus Dick Schulze and current Chairman and CEO Hubert Joly to talk about how we got to where we are today and get a glimpse into where we’re going next.\n Sound of Music\n22 Aug: Best Buy at 50: A Q&A with Founder Dick Schulze and CEO Hubert Joly\nTechnology has changed a lot over the past half century, and so has Best Buy.\n 14 Jun: 35 Years Ago Today, A Tornado Transformed Best Buy\nOn the afternoon of June 14, 1981, a tornado slammed into the Minneapolis suburbs, mere miles from where the Best Buy corporate headquarters now stands.\n Little did he know that it would become Best Buy, a nearly $40 billion company that now sells everything from TVs and laptops to drones and virtual-reality headsets.\n It was the most significant tornado to hit the Minneapolis-St. Paul area in 20 years — and its wake would change the path of our company.\n'}, {'url': 'https://historydraft.com/story/best-buy/timeline/841', 'content': "Best Buy announced the shutdown of the Future Shop chain in Canada\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.\n Best Buy Company, Inc\nIn 1983, with seven stores and $10 million in annual sales, Sound of Music was renamed Best Buy Company, Inc.\nBest Buy debuted on the New York Stock Exchange\nBest Buy was taken public in 1985, and two years later it debuted on the New York Stock Exchange.\n The company closed all of its Best Buy-branded stores in China\nThe company closed all of its Best Buy-branded stores in China by February 2011, when it merged Best Buy China's operations with Jiangsu Five Star, which had become a wholly-owned subsidiary of Best Buy in 2009.\n Best Buy announced that it would start selling musical instruments and related gear in over 80 of its retail stores\nIn July 2008, Best Buy announced that it would start selling musical instruments and related gear in over 80 of its retail stores, making the company the second-largest musical-instrument distributor in the US.\n Best Buy hired Virtucom Group to revamp Best Buy's website and handle all of the company's online content\nIn January 2004, Best Buy hired Virtucom Group to revamp Best Buy's website and handle all of the company's online content.\n"}, {'url': 'https://en.wikipedia.org/wiki/Best_Buy', 'content': 'Under the Geek Squad brand, Best Buy offers computer repair, warranty service, and accidental service plans.[2] Best Buy provides an online community forum for members, where consumers can discuss product experiences, ask questions, and get answers from other members or retail product experts.[82]\nThe building exteriors of Best Buy-branded stores are typically light brown, with the entrance designed to look like a blue box emerging from the structure.[83] Corporate employees operated under a results only work environment from 2005 until March 2013, when the management style was abandoned by Best Buy CEO Hubert Joly.[84][85]\nAs of October 29, 2016, Best Buy operated 1,026 Best Buy, 331 Best Buy Mobile stand-alone stores, and 28 stand-alone Pacific Sales stores in the US.[2] Best Buy also operated: 135 Best Buy and 53 Best Buy Mobile stand-alone stores in Canada; and 18 Best Buy stores and 5 Best Buy Express stores in Mexico.[2] Best Buy exited the European market in April 2013, selling its stake in the business back to its partner Carphone Warehouse.[71][72]\nHouse brands[edit]\nBest Buy also produces products under eight house brands:[2]\nControversies[edit]\nWarranty[edit]\n The company, in announcing the result, said it was focusing more on digital media in its marketing, moving away from newspaper, magazine, and television advertising.[73]\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.[74]\nOn March 1, 2018, the company announced that it would shut down its 250 standalone Best Buy Mobile stores in the United States by the end of May, due to low revenue and high costs. In August 2022, Best Buy said it would be laying off employees across the country after warnings of weaker sales, and the company cut its forecast for the remainder of 2022.[79]\nOn October 13, 2023, Best Buy announced that it would phase out the sale of physical home media in early 2024, citing changes in the market due to the prevalence of streaming video on demand services.[80][81]\nCorporate affairs[edit]\nBusiness operations[edit]\nBest Buy sells consumer electronics and a variety of related merchandise, including software, video games, music, mobile phones, digital cameras, car stereos, and video cameras, in addition to home appliances (washing machines, dryers, and refrigerators), in a noncommissioned sales environment.[2] The Best Buy Mobile stores were reported to account for 1% of the company\'s revenue.[75]\nOn May 9, 2018, the company unveiled a new logo for the first time in nearly three decades.[76]\nOn July 2, 2018, Best Buy announced it was cutting the amount of store space devoted to selling physical music, citing the popularity of streaming services as having reduced sales.[77]\nOn April 15, 2019, Best Buy announced that in June 2019, its current CFO, Corie Barry, would replace Hubert Joly[5] who held the position of CEO since August 2012. The customer was indicted for possession of child pornography, although the judge in the case later threw out nearly all the evidence against the defendant due to "false and misleading statements" made by an FBI agent while trying to secure a search warrant for the customer\'s house, and the government ultimately dropped the case.[97]\nPrivacy[edit]\nOn October 20, 2023, CBC News released the results of a Marketplace investigation which found that that Best Buy technicians had viewed private files, such as intimate photos, on customer devices.'}, {'url': 'https://www.company-histories.com/Best-Buy-Co-Inc-Company-History.html', 'content': 'As the Best Buy chain pushed past the 500-store mark in 2003 with the opening of 67 new stores in the United States, including the first stores in Alaska, Idaho, Utah, and West Virginia, the situation at the Musicland chains was deteriorating. Returning to the Core: 2003 and Beyond\nDespite the completion of this acquisition, Best Buy pushed ahead with a previously planned expansion of the Best Buy chain into Canada, opening eight stores in the Toronto area in the fall of 2002. Significant changes were made to the product mix, particularly by eliminating slower selling product lines and models; a greater emphasis was placed on selling service plans to customers; and "high touch" areas were added to the stores to help sell the burgeoning array of digital consumer products, such as cameras, cellular phones, satellite systems, and the fast-selling DVD player (first introduced in 1996) for which customers often needed more assistance. This rapid growth in digital product sales also inspired a shift in the overall product mix: sales of consumer electronics products (33 percent of the total) surpassed the sales of home office products (31 percent) for the first time (in 1999 these figures were 27 percent and 36 percent, respectively). Magnolia was founded in 1954 by Len Tweten, who built the firm into one of the most respected audio-video retailers in the nation based on the high quality of its merchandise, its dedication to exceptional customer service, and its renowned in-house repair/installation department.'}][0m[32;1m[1;3m
-I have found that Best Buy was founded as Sound of Music. Now, I will search for the year it went public and its stock price in 2000 and 2010.
-{'tool_name': 'internet_search', 'parameters': {'query': 'Best Buy went public'}}
-[0m[36;1m[1;3m[{'url': 'https://www.zippia.com/best-buy-careers-1455/history/', 'content': 'Meantime, Best Buy was taken public in 1985, raising $8 million through an IPO, and two years later gained a listing on the New York Stock Exchange (NYSE). ... Best Buy may also be known as or be related to Best Buy, Best Buy Co Inc, Best Buy Co., Inc., Sound of Music (1966-1983) Best Buy Co. Superstores (1983-1984) Best Buy Superstores ...'}, {'url': 'https://atouchofbusiness.com/companies/best-buy/', 'content': 'Public Listing and IPO: Best Buy went public in 1985 and listed on the NYSE in 1987. Conceptual Changes: The late 1980s and 1990s brought new store formats and growth, with revenues surpassing $1 billion. Overcoming Market Challenges. Supplier Relations: Mid-1990s challenges led to a merchandising revamp.'}, {'url': 'https://www.encyclopedia.com/social-sciences-and-law/economics-business-and-labor/businesses-and-occupations/best-buy-co-inc', 'content': 'Best Buy grew rapidly with $28.5 million in sales in 1984—compared to $9.9 million in 1983. In 1985, with 9 stores, Best Buy became a public company. By 1987, Best Buy had 24 stores and sales of $240 million, but it was beginning to feel the crunch as other rapidly expanding consumer electronics retailers pushed their way into the market.'}, {'url': 'https://www.company-histories.com/Best-Buy-Co-Inc-Company-History.html', 'content': 'As the Best Buy chain pushed past the 500-store mark in 2003 with the opening of 67 new stores in the United States, including the first stores in Alaska, Idaho, Utah, and West Virginia, the situation at the Musicland chains was deteriorating. Returning to the Core: 2003 and Beyond\nDespite the completion of this acquisition, Best Buy pushed ahead with a previously planned expansion of the Best Buy chain into Canada, opening eight stores in the Toronto area in the fall of 2002. Significant changes were made to the product mix, particularly by eliminating slower selling product lines and models; a greater emphasis was placed on selling service plans to customers; and "high touch" areas were added to the stores to help sell the burgeoning array of digital consumer products, such as cameras, cellular phones, satellite systems, and the fast-selling DVD player (first introduced in 1996) for which customers often needed more assistance. This rapid growth in digital product sales also inspired a shift in the overall product mix: sales of consumer electronics products (33 percent of the total) surpassed the sales of home office products (31 percent) for the first time (in 1999 these figures were 27 percent and 36 percent, respectively). Magnolia was founded in 1954 by Len Tweten, who built the firm into one of the most respected audio-video retailers in the nation based on the high quality of its merchandise, its dedication to exceptional customer service, and its renowned in-house repair/installation department.'}, {'url': 'https://en.wikipedia.org/wiki/Best_Buy', 'content': 'Under the Geek Squad brand, Best Buy offers computer repair, warranty service, and accidental service plans.[2] Best Buy provides an online community forum for members, where consumers can discuss product experiences, ask questions, and get answers from other members or retail product experts.[82]\nThe building exteriors of Best Buy-branded stores are typically light brown, with the entrance designed to look like a blue box emerging from the structure.[83] Corporate employees operated under a results only work environment from 2005 until March 2013, when the management style was abandoned by Best Buy CEO Hubert Joly.[84][85]\nAs of October 29, 2016, Best Buy operated 1,026 Best Buy, 331 Best Buy Mobile stand-alone stores, and 28 stand-alone Pacific Sales stores in the US.[2] Best Buy also operated: 135 Best Buy and 53 Best Buy Mobile stand-alone stores in Canada; and 18 Best Buy stores and 5 Best Buy Express stores in Mexico.[2] Best Buy exited the European market in April 2013, selling its stake in the business back to its partner Carphone Warehouse.[71][72]\nHouse brands[edit]\nBest Buy also produces products under eight house brands:[2]\nControversies[edit]\nWarranty[edit]\n The company, in announcing the result, said it was focusing more on digital media in its marketing, moving away from newspaper, magazine, and television advertising.[73]\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.[74]\nOn March 1, 2018, the company announced that it would shut down its 250 standalone Best Buy Mobile stores in the United States by the end of May, due to low revenue and high costs. In August 2022, Best Buy said it would be laying off employees across the country after warnings of weaker sales, and the company cut its forecast for the remainder of 2022.[79]\nOn October 13, 2023, Best Buy announced that it would phase out the sale of physical home media in early 2024, citing changes in the market due to the prevalence of streaming video on demand services.[80][81]\nCorporate affairs[edit]\nBusiness operations[edit]\nBest Buy sells consumer electronics and a variety of related merchandise, including software, video games, music, mobile phones, digital cameras, car stereos, and video cameras, in addition to home appliances (washing machines, dryers, and refrigerators), in a noncommissioned sales environment.[2] The Best Buy Mobile stores were reported to account for 1% of the company\'s revenue.[75]\nOn May 9, 2018, the company unveiled a new logo for the first time in nearly three decades.[76]\nOn July 2, 2018, Best Buy announced it was cutting the amount of store space devoted to selling physical music, citing the popularity of streaming services as having reduced sales.[77]\nOn April 15, 2019, Best Buy announced that in June 2019, its current CFO, Corie Barry, would replace Hubert Joly[5] who held the position of CEO since August 2012. The customer was indicted for possession of child pornography, although the judge in the case later threw out nearly all the evidence against the defendant due to "false and misleading statements" made by an FBI agent while trying to secure a search warrant for the customer\'s house, and the government ultimately dropped the case.[97]\nPrivacy[edit]\nOn October 20, 2023, CBC News released the results of a Marketplace investigation which found that that Best Buy technicians had viewed private files, such as intimate photos, on customer devices.'}][0m[32;1m[1;3m
-{'tool_name': 'internet_search', 'parameters': {'query': 'Best Buy stock price in 2000 and 2010'}}
-[0m[36;1m[1;3m[{'url': 'https://finance.yahoo.com/quote/BBY/history/', 'content': 'Discover historical prices for BBY stock on Yahoo Finance. View daily, weekly or monthly format back to when Best Buy Co., Inc. stock was issued.'}, {'url': 'https://www.macrotrends.net/stocks/charts/BBY/best-buy/stock-price-history', 'content': 'Best Buy - 39 Year Stock Price History | BBY. Prices ... 2010, 25.1877, 25.7674, 31.2441, 20.2713, 22.3228 ... 2000, 16.0083, 15.2882, 22.8658, 5.9318, 7.8595, -\xa0...'}, {'url': 'https://investors.bestbuy.com/investor-relations/stock-info/quote-and-chart/', 'content': 'Price 79.30. Change -0.88. Volume 666,622.'}, {'url': 'https://companiesmarketcap.com/best-buy/stock-price-history/', 'content': 'Stock price history for Best Buy (BBY). Highest end of day price: $138.00 USD on 2021-11-22. Lowest end of day price: $0.14 USD on 1985-05-02\xa0...'}, {'url': 'https://www.netcials.com/stock-price-chart-history-nyse/BBY-Best-Buy-Co-Inc/', 'content': '1 Best Buy Co Inc (BBY) 20 Years Stock Chart History ; 2000, 16.24 (17.6%), 23.199 (29.07%) ; 2001, 14.80 (-8.87%), 20.1319 (-13.22%) ; 2002, 14.59 (-1.42%)\xa0...'}][0m[32;1m[1;3mRelevant Documents: 0,1,2,3,4,5,6,7,11,13,14
-Cited Documents: 0,1,2,3,4,5,6,7,11,14
-Answer: Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.
-Grounded answer: Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for the company that was founded as Sound of Music. Then, I will search for the year it went public. Finally, I will search for its stock price in 2000 and 2010.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'company founded as Sound of Music'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.mprnews.org/story/2012/05/15/best-buy-richard-schulze-legacy', 'content': 'Amazon is taking a piece of everyone\'s business,"\nSome analysts have questioned the extent to which Schulze\'s strong hand over the company has held it back in the face of digital competition. "\nSchulze hit on the "Best Buy" strategy when a twister ripped open a store and the company held a huge sale with low prices and lots of promotion. And Richard Schulz was able to outthink and outmaneuver the competition to put up Best Buy as the definitive place in the brick-and-mortar world to buy electronic equipment," Spector said.\n Best Buy\'s Richard Schulze: Stereo seller to retail giant\nShare\nIn 1966, Best Buy was a stereo specialty retailer called Sound of Music, founded by Richard Schulze in St. Paul.\n Former CEO Anderson said it is possible that Schulze\'s goals for the company were out of touch with the digital age, and that Schulze may have stuck around too long.\n'}, {'url': 'https://corporate.bestbuy.com/tag/sound-of-music/', 'content': 'As we celebrate Best Buy’s 50th anniversary, we sat down with founder and Chairman Emeritus Dick Schulze and current Chairman and CEO Hubert Joly to talk about how we got to where we are today and get a glimpse into where we’re going next.\n Sound of Music\n22 Aug: Best Buy at 50: A Q&A with Founder Dick Schulze and CEO Hubert Joly\nTechnology has changed a lot over the past half century, and so has Best Buy.\n 14 Jun: 35 Years Ago Today, A Tornado Transformed Best Buy\nOn the afternoon of June 14, 1981, a tornado slammed into the Minneapolis suburbs, mere miles from where the Best Buy corporate headquarters now stands.\n Little did he know that it would become Best Buy, a nearly $40 billion company that now sells everything from TVs and laptops to drones and virtual-reality headsets.\n It was the most significant tornado to hit the Minneapolis-St. Paul area in 20 years — and its wake would change the path of our company.\n'}, {'url': 'https://historydraft.com/story/best-buy/timeline/841', 'content': "Best Buy announced the shutdown of the Future Shop chain in Canada\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.\n Best Buy Company, Inc\nIn 1983, with seven stores and $10 million in annual sales, Sound of Music was renamed Best Buy Company, Inc.\nBest Buy debuted on the New York Stock Exchange\nBest Buy was taken public in 1985, and two years later it debuted on the New York Stock Exchange.\n The company closed all of its Best Buy-branded stores in China\nThe company closed all of its Best Buy-branded stores in China by February 2011, when it merged Best Buy China's operations with Jiangsu Five Star, which had become a wholly-owned subsidiary of Best Buy in 2009.\n Best Buy announced that it would start selling musical instruments and related gear in over 80 of its retail stores\nIn July 2008, Best Buy announced that it would start selling musical instruments and related gear in over 80 of its retail stores, making the company the second-largest musical-instrument distributor in the US.\n Best Buy hired Virtucom Group to revamp Best Buy's website and handle all of the company's online content\nIn January 2004, Best Buy hired Virtucom Group to revamp Best Buy's website and handle all of the company's online content.\n"}, {'url': 'https://en.wikipedia.org/wiki/Best_Buy', 'content': 'Under the Geek Squad brand, Best Buy offers computer repair, warranty service, and accidental service plans.[2] Best Buy provides an online community forum for members, where consumers can discuss product experiences, ask questions, and get answers from other members or retail product experts.[82]\nThe building exteriors of Best Buy-branded stores are typically light brown, with the entrance designed to look like a blue box emerging from the structure.[83] Corporate employees operated under a results only work environment from 2005 until March 2013, when the management style was abandoned by Best Buy CEO Hubert Joly.[84][85]\nAs of October 29, 2016, Best Buy operated 1,026 Best Buy, 331 Best Buy Mobile stand-alone stores, and 28 stand-alone Pacific Sales stores in the US.[2] Best Buy also operated: 135 Best Buy and 53 Best Buy Mobile stand-alone stores in Canada; and 18 Best Buy stores and 5 Best Buy Express stores in Mexico.[2] Best Buy exited the European market in April 2013, selling its stake in the business back to its partner Carphone Warehouse.[71][72]\nHouse brands[edit]\nBest Buy also produces products under eight house brands:[2]\nControversies[edit]\nWarranty[edit]\n The company, in announcing the result, said it was focusing more on digital media in its marketing, moving away from newspaper, magazine, and television advertising.[73]\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.[74]\nOn March 1, 2018, the company announced that it would shut down its 250 standalone Best Buy Mobile stores in the United States by the end of May, due to low revenue and high costs. In August 2022, Best Buy said it would be laying off employees across the country after warnings of weaker sales, and the company cut its forecast for the remainder of 2022.[79]\nOn October 13, 2023, Best Buy announced that it would phase out the sale of physical home media in early 2024, citing changes in the market due to the prevalence of streaming video on demand services.[80][81]\nCorporate affairs[edit]\nBusiness operations[edit]\nBest Buy sells consumer electronics and a variety of related merchandise, including software, video games, music, mobile phones, digital cameras, car stereos, and video cameras, in addition to home appliances (washing machines, dryers, and refrigerators), in a noncommissioned sales environment.[2] The Best Buy Mobile stores were reported to account for 1% of the company\'s revenue.[75]\nOn May 9, 2018, the company unveiled a new logo for the first time in nearly three decades.[76]\nOn July 2, 2018, Best Buy announced it was cutting the amount of store space devoted to selling physical music, citing the popularity of streaming services as having reduced sales.[77]\nOn April 15, 2019, Best Buy announced that in June 2019, its current CFO, Corie Barry, would replace Hubert Joly[5] who held the position of CEO since August 2012. The customer was indicted for possession of child pornography, although the judge in the case later threw out nearly all the evidence against the defendant due to "false and misleading statements" made by an FBI agent while trying to secure a search warrant for the customer\'s house, and the government ultimately dropped the case.[97]\nPrivacy[edit]\nOn October 20, 2023, CBC News released the results of a Marketplace investigation which found that that Best Buy technicians had viewed private files, such as intimate photos, on customer devices.'}, {'url': 'https://www.company-histories.com/Best-Buy-Co-Inc-Company-History.html', 'content': 'As the Best Buy chain pushed past the 500-store mark in 2003 with the opening of 67 new stores in the United States, including the first stores in Alaska, Idaho, Utah, and West Virginia, the situation at the Musicland chains was deteriorating. Returning to the Core: 2003 and Beyond\nDespite the completion of this acquisition, Best Buy pushed ahead with a previously planned expansion of the Best Buy chain into Canada, opening eight stores in the Toronto area in the fall of 2002. Significant changes were made to the product mix, particularly by eliminating slower selling product lines and models; a greater emphasis was placed on selling service plans to customers; and "high touch" areas were added to the stores to help sell the burgeoning array of digital consumer products, such as cameras, cellular phones, satellite systems, and the fast-selling DVD player (first introduced in 1996) for which customers often needed more assistance. This rapid growth in digital product sales also inspired a shift in the overall product mix: sales of consumer electronics products (33 percent of the total) surpassed the sales of home office products (31 percent) for the first time (in 1999 these figures were 27 percent and 36 percent, respectively). Magnolia was founded in 1954 by Len Tweten, who built the firm into one of the most respected audio-video retailers in the nation based on the high quality of its merchandise, its dedication to exceptional customer service, and its renowned in-house repair/installation department.'}][0m[32;1m[1;3m
+ I have found that Best Buy was founded as Sound of Music. Now, I will search for the year it went public and its stock price in 2000 and 2010.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'Best Buy went public'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.zippia.com/best-buy-careers-1455/history/', 'content': 'Meantime, Best Buy was taken public in 1985, raising $8 million through an IPO, and two years later gained a listing on the New York Stock Exchange (NYSE). ... Best Buy may also be known as or be related to Best Buy, Best Buy Co Inc, Best Buy Co., Inc., Sound of Music (1966-1983) Best Buy Co. Superstores (1983-1984) Best Buy Superstores ...'}, {'url': 'https://atouchofbusiness.com/companies/best-buy/', 'content': 'Public Listing and IPO: Best Buy went public in 1985 and listed on the NYSE in 1987. Conceptual Changes: The late 1980s and 1990s brought new store formats and growth, with revenues surpassing $1 billion. Overcoming Market Challenges. Supplier Relations: Mid-1990s challenges led to a merchandising revamp.'}, {'url': 'https://www.encyclopedia.com/social-sciences-and-law/economics-business-and-labor/businesses-and-occupations/best-buy-co-inc', 'content': 'Best Buy grew rapidly with $28.5 million in sales in 1984—compared to $9.9 million in 1983. In 1985, with 9 stores, Best Buy became a public company. By 1987, Best Buy had 24 stores and sales of $240 million, but it was beginning to feel the crunch as other rapidly expanding consumer electronics retailers pushed their way into the market.'}, {'url': 'https://www.company-histories.com/Best-Buy-Co-Inc-Company-History.html', 'content': 'As the Best Buy chain pushed past the 500-store mark in 2003 with the opening of 67 new stores in the United States, including the first stores in Alaska, Idaho, Utah, and West Virginia, the situation at the Musicland chains was deteriorating. Returning to the Core: 2003 and Beyond\nDespite the completion of this acquisition, Best Buy pushed ahead with a previously planned expansion of the Best Buy chain into Canada, opening eight stores in the Toronto area in the fall of 2002. Significant changes were made to the product mix, particularly by eliminating slower selling product lines and models; a greater emphasis was placed on selling service plans to customers; and "high touch" areas were added to the stores to help sell the burgeoning array of digital consumer products, such as cameras, cellular phones, satellite systems, and the fast-selling DVD player (first introduced in 1996) for which customers often needed more assistance. This rapid growth in digital product sales also inspired a shift in the overall product mix: sales of consumer electronics products (33 percent of the total) surpassed the sales of home office products (31 percent) for the first time (in 1999 these figures were 27 percent and 36 percent, respectively). Magnolia was founded in 1954 by Len Tweten, who built the firm into one of the most respected audio-video retailers in the nation based on the high quality of its merchandise, its dedication to exceptional customer service, and its renowned in-house repair/installation department.'}, {'url': 'https://en.wikipedia.org/wiki/Best_Buy', 'content': 'Under the Geek Squad brand, Best Buy offers computer repair, warranty service, and accidental service plans.[2] Best Buy provides an online community forum for members, where consumers can discuss product experiences, ask questions, and get answers from other members or retail product experts.[82]\nThe building exteriors of Best Buy-branded stores are typically light brown, with the entrance designed to look like a blue box emerging from the structure.[83] Corporate employees operated under a results only work environment from 2005 until March 2013, when the management style was abandoned by Best Buy CEO Hubert Joly.[84][85]\nAs of October 29, 2016, Best Buy operated 1,026 Best Buy, 331 Best Buy Mobile stand-alone stores, and 28 stand-alone Pacific Sales stores in the US.[2] Best Buy also operated: 135 Best Buy and 53 Best Buy Mobile stand-alone stores in Canada; and 18 Best Buy stores and 5 Best Buy Express stores in Mexico.[2] Best Buy exited the European market in April 2013, selling its stake in the business back to its partner Carphone Warehouse.[71][72]\nHouse brands[edit]\nBest Buy also produces products under eight house brands:[2]\nControversies[edit]\nWarranty[edit]\n The company, in announcing the result, said it was focusing more on digital media in its marketing, moving away from newspaper, magazine, and television advertising.[73]\nOn March 28, 2015, Best Buy announced the shutdown of the Future Shop chain in Canada; 65 of its 131 former locations were converted into Best Buy locations, while the rest (primarily those in close proximity to an existing Best Buy) were closed permanently.[74]\nOn March 1, 2018, the company announced that it would shut down its 250 standalone Best Buy Mobile stores in the United States by the end of May, due to low revenue and high costs. In August 2022, Best Buy said it would be laying off employees across the country after warnings of weaker sales, and the company cut its forecast for the remainder of 2022.[79]\nOn October 13, 2023, Best Buy announced that it would phase out the sale of physical home media in early 2024, citing changes in the market due to the prevalence of streaming video on demand services.[80][81]\nCorporate affairs[edit]\nBusiness operations[edit]\nBest Buy sells consumer electronics and a variety of related merchandise, including software, video games, music, mobile phones, digital cameras, car stereos, and video cameras, in addition to home appliances (washing machines, dryers, and refrigerators), in a noncommissioned sales environment.[2] The Best Buy Mobile stores were reported to account for 1% of the company\'s revenue.[75]\nOn May 9, 2018, the company unveiled a new logo for the first time in nearly three decades.[76]\nOn July 2, 2018, Best Buy announced it was cutting the amount of store space devoted to selling physical music, citing the popularity of streaming services as having reduced sales.[77]\nOn April 15, 2019, Best Buy announced that in June 2019, its current CFO, Corie Barry, would replace Hubert Joly[5] who held the position of CEO since August 2012. The customer was indicted for possession of child pornography, although the judge in the case later threw out nearly all the evidence against the defendant due to "false and misleading statements" made by an FBI agent while trying to secure a search warrant for the customer\'s house, and the government ultimately dropped the case.[97]\nPrivacy[edit]\nOn October 20, 2023, CBC News released the results of a Marketplace investigation which found that that Best Buy technicians had viewed private files, such as intimate photos, on customer devices.'}][0m[32;1m[1;3m
+ {'tool_name': 'internet_search', 'parameters': {'query': 'Best Buy stock price in 2000 and 2010'}}
+ [0m[36;1m[1;3m[{'url': 'https://finance.yahoo.com/quote/BBY/history/', 'content': 'Discover historical prices for BBY stock on Yahoo Finance. View daily, weekly or monthly format back to when Best Buy Co., Inc. stock was issued.'}, {'url': 'https://www.macrotrends.net/stocks/charts/BBY/best-buy/stock-price-history', 'content': 'Best Buy - 39 Year Stock Price History | BBY. Prices ... 2010, 25.1877, 25.7674, 31.2441, 20.2713, 22.3228 ... 2000, 16.0083, 15.2882, 22.8658, 5.9318, 7.8595, -\xa0...'}, {'url': 'https://investors.bestbuy.com/investor-relations/stock-info/quote-and-chart/', 'content': 'Price 79.30. Change -0.88. Volume 666,622.'}, {'url': 'https://companiesmarketcap.com/best-buy/stock-price-history/', 'content': 'Stock price history for Best Buy (BBY). Highest end of day price: $138.00 USD on 2021-11-22. Lowest end of day price: $0.14 USD on 1985-05-02\xa0...'}, {'url': 'https://www.netcials.com/stock-price-chart-history-nyse/BBY-Best-Buy-Co-Inc/', 'content': '1 Best Buy Co Inc (BBY) 20 Years Stock Chart History ; 2000, 16.24 (17.6%), 23.199 (29.07%) ; 2001, 14.80 (-8.87%), 20.1319 (-13.22%) ; 2002, 14.59 (-1.42%)\xa0...'}][0m[32;1m[1;3mRelevant Documents: 0,1,2,3,4,5,6,7,11,13,14
+ Cited Documents: 0,1,2,3,4,5,6,7,11,14
+ Answer: Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.
+ Grounded answer: Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.[0m
+
+ [1m> Finished chain.[0m
+
+
+
-[1m> Finished chain.[0m
+ 'Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.'
-'Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.'
+```python
+
```
## Have a multi-turn conversation with the ReAct agent
-
The chat history enables you to have multi-turn conversations with the ReAct agent.
-```python PYTHON
+
+```python
+# Step 1: Construct the chat history as a list of LangChain Messages, ending with the last user message
from langchain_core.messages import HumanMessage, AIMessage
chat_history = [
@@ -533,7 +592,10 @@ chat_history = [
prompt = ChatPromptTemplate.from_messages(chat_history)
```
-```python PYTHON
+
+```python
+# Step 2: When you make the agent, specify the chat_history as the prompt, e.g.
+# Create the ReAct agent
agent = create_cohere_react_agent(
llm=llm,
tools=[internet_search, vectorstore_search, python_tool],
@@ -543,7 +605,9 @@ agent = create_cohere_react_agent(
agent_executor = AgentExecutor(agent=agent, tools=[internet_search, vectorstore_search, python_tool], verbose=True)
```
-```python PYTHON
+
+```python
+# Step 3: When you invoke the agent_executor there's no need to pass anything else into invoke
response = agent_executor.invoke({
"preamble": preamble,
})
@@ -551,31 +615,43 @@ response = agent_executor.invoke({
response['output']
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will search for 'Oracle CRM offering' and relay the information I find to the user.
-{'tool_name': 'internet_search', 'parameters': {'query': 'Oracle CRM offering'}}
-[0m[36;1m[1;3m[{'url': 'https://docs.oracle.com/en/applications/siebel/', 'content': 'Siebel CRM delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations. With solutions tailored to more than 20 industries, Siebel CRM delivers comprehensive on-premise CRM solutions that are tailored industry solutions with role-based customer intelligence and pre-built integration.'}, {'url': 'https://www.softwareadvice.com/resources/breaking-down-oracle-crm/', 'content': "Oracle's Marketing Cloud provides a comprehensive set of tools that cover a range of digital marketing needs. This includes tools for cross-channel marketing, i.e., marketing automation for both B2B and B2C marketers, as well as data management, content marketing and social media marketing. Cross-Channel Marketing."}, {'url': 'https://www.trustradius.com/products/oracle-crm-on-demand/reviews?qs=pros-and-cons', 'content': "What is Oracle CRM On Demand?The basis of this offering is the Market2Lead product that Oracle acquired in 2010. It has now been fully integrated with Oracle's On Demand CRM product and is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI."}, {'url': 'https://www.oracle.com/cx/siebel/', 'content': 'In addition to standard CRM functionality, this industry solution includes asset, premises, and contracts management; work orders; oil well management and oil field service; B2C and B2B web portals; and credit and fraud management capabilities.\nDesigned for pharmaceutical sales, Siebel CRM Life Sciences provides personalized content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction.\n Marketing, sales, and customer service applications are fully integrated and designed to manage the complex interactions and relationships between brand owners, their partners (including brokers and distributors), their customers, and the end consumer.\n It leverages data and AI to transform CX–launching offers, acquiring and retaining customers, omnichannel ecommerce and customer care, and fulfilling and monetizing services.\n It leverages data and AI to transform CX–launching offers, acquiring and retaining customers, omnichannel ecommerce and customer care, and fulfilling and monetizing services.\n Provide world-class citizen services while delivering comprehensive, cost-efficient case management and policy management, including social services, justice and public safety, constituent services/311, self-service citizen portals, tax and revenue, and licensing and permitting.\n'}, {'url': 'https://www.suretysystems.com/insights/oracle-customer-relationship-management-a-complete-overview/', 'content': 'Effective CRM systems offer the following features for enterprise users: Simple, easy-to-use interface; ... Oracle CRM simplifies customer relationship management by enhancing customer interactions and improving customer satisfaction and sales growth. Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM ...'}][0m[32;1m[1;3mRelevant Documents: 0,1,2,3,4
-Cited Documents: 0,1,2,3,4
-Answer: Oracle's CRM offering includes the following:
-- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing
-- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI
-- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries
-- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction
-- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM
-Grounded answer: Oracle's CRM offering includes the following:
-- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing
-- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI
-- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries
-- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction
-- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for 'Oracle CRM offering' and relay the information I find to the user.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'Oracle CRM offering'}}
+ [0m[36;1m[1;3m[{'url': 'https://docs.oracle.com/en/applications/siebel/', 'content': 'Siebel CRM delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations. With solutions tailored to more than 20 industries, Siebel CRM delivers comprehensive on-premise CRM solutions that are tailored industry solutions with role-based customer intelligence and pre-built integration.'}, {'url': 'https://www.softwareadvice.com/resources/breaking-down-oracle-crm/', 'content': "Oracle's Marketing Cloud provides a comprehensive set of tools that cover a range of digital marketing needs. This includes tools for cross-channel marketing, i.e., marketing automation for both B2B and B2C marketers, as well as data management, content marketing and social media marketing. Cross-Channel Marketing."}, {'url': 'https://www.trustradius.com/products/oracle-crm-on-demand/reviews?qs=pros-and-cons', 'content': "What is Oracle CRM On Demand?The basis of this offering is the Market2Lead product that Oracle acquired in 2010. It has now been fully integrated with Oracle's On Demand CRM product and is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI."}, {'url': 'https://www.oracle.com/cx/siebel/', 'content': 'In addition to standard CRM functionality, this industry solution includes asset, premises, and contracts management; work orders; oil well management and oil field service; B2C and B2B web portals; and credit and fraud management capabilities.\nDesigned for pharmaceutical sales, Siebel CRM Life Sciences provides personalized content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction.\n Marketing, sales, and customer service applications are fully integrated and designed to manage the complex interactions and relationships between brand owners, their partners (including brokers and distributors), their customers, and the end consumer.\n It leverages data and AI to transform CX–launching offers, acquiring and retaining customers, omnichannel ecommerce and customer care, and fulfilling and monetizing services.\n It leverages data and AI to transform CX–launching offers, acquiring and retaining customers, omnichannel ecommerce and customer care, and fulfilling and monetizing services.\n Provide world-class citizen services while delivering comprehensive, cost-efficient case management and policy management, including social services, justice and public safety, constituent services/311, self-service citizen portals, tax and revenue, and licensing and permitting.\n'}, {'url': 'https://www.suretysystems.com/insights/oracle-customer-relationship-management-a-complete-overview/', 'content': 'Effective CRM systems offer the following features for enterprise users: Simple, easy-to-use interface; ... Oracle CRM simplifies customer relationship management by enhancing customer interactions and improving customer satisfaction and sales growth. Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM ...'}][0m[32;1m[1;3mRelevant Documents: 0,1,2,3,4
+ Cited Documents: 0,1,2,3,4
+ Answer: Oracle's CRM offering includes the following:
+ - Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing
+ - CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI
+ - Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries
+ - Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction
+ - Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM
+ Grounded answer: Oracle's CRM offering includes the following:
+ - Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing
+ - CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI
+ - Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries
+ - Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction
+ - Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM[0m
+
+ [1m> Finished chain.[0m
+
+
-[1m> Finished chain.[0m
+ "Oracle's CRM offering includes the following:\n- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing\n- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI\n- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries\n- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction\n- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM"
+
+
+
+
+```python
+
+```
+```python
-"Oracle's CRM offering includes the following:\n- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing\n- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI\n- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries\n- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction\n- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM"
```
diff --git a/fern/pages/cookbooks/basic-rag.mdx b/fern/pages/cookbooks/basic-rag.mdx
index bc1ac3e5f..4e0a4453d 100644
--- a/fern/pages/cookbooks/basic-rag.mdx
+++ b/fern/pages/cookbooks/basic-rag.mdx
@@ -1,70 +1,79 @@
---
-title: "Basic RAG: Retrieval-Augmented Generation with Cohere"
+title: Basic RAG
slug: /page/basic-rag
description: "This page describes how to work with Cohere's basic retrieval-augmented generation functionality."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG, AI agents"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
Retrieval-Augmented Generation (RAG) is a technique that combines the strengths of pre-trained language models with the ability to retrieve information from a large corpus of documents. RAG **enables the language model to produce more informed, accurate, and contextually relevant answers** than by relying on its pre-trained knowledge alone.
At Cohere, all RAG calls come with... **precise citations**! 🎉
The model cites which groups of words, in the RAG chunks, were used to generate the final answer.
-These citations make it easy to check where the model’s generated response claims are coming from and they help users gain visibility into the model reasoning.
+These citations make it easy to check where the model’s generated response claims are coming from and they help users gain visibility into the model reasoning.
RAG consists of 3 steps:
-
- Step 1: Indexing and given a user query, retrieve the relevant chunks from the index
- Step 2: Optionally, rerank the retrieved chunks
- Step 3: Generate the model final answer with **precise citations**, given the retrieved and reranked chunks
-## Step 0 - Imports & Getting some data
-In this example, we'll use a recent piece of text, that wasn't in the training data: the Wikipedia page of the movie "Dune 2".
+
+
+## Step 0 - Imports & Getting some data
+
+In this example, we'll use a recent piece of text, that wasn't in the training data: the Wikipedia page of the movie "Dune 2".
In practice, you would typically do RAG on much longer text, that doesn't fit in the context window of the model.
-```python PYTHON
+
+```python
+# we'll use Cohere to cover all building blocks of RAG
+# TODO: upgrade to "cohere>5"
%pip install "cohere<5" --quiet
```
-```txt title="Output"
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m52.8/52.8 kB[0m [31m1.6 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m33.6 MB/s[0m eta [36m0:00:00[0m
-[?25h
-```
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m52.8/52.8 kB[0m [31m1.6 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m33.6 MB/s[0m eta [36m0:00:00[0m
+ [?25h
-```python PYTHON
+
+```python
import cohere
API_KEY = "..." # fill in your Cohere API key here
co = cohere.Client(API_KEY)
```
-```python PYTHON
+
+```python
+# we'll get some wikipedia data
!pip install wikipedia --quiet
import wikipedia
```
-```txt title="Output"
-Preparing metadata (setup.py) ... [?25l[?25hdone
-Building wheel for wikipedia (setup.py) ... [?25l[?25hdone
-```
+ Preparing metadata (setup.py) ... [?25l[?25hdone
+ Building wheel for wikipedia (setup.py) ... [?25l[?25hdone
-```python PYTHON
+
+
+```python
+# let's get the wikipedia article about Dune Part Two
article = wikipedia.page('Dune Part Two')
text = article.content
print(f"The text has roughly {len(text.split())} words.")
```
-```txt title="Output"
-The text has roughly 5323 words.
-```
+ The text has roughly 5323 words.
+
## Step 1 - Indexing and given a user query, retrieve the relevant chunks from the index
@@ -72,19 +81,21 @@ We index the document in a vector database. This requires getting the documents,
### We split the document into chunks of roughly 512 words
-```python PYTHON
+
+```python
+# For chunking let's use langchain to help us split the text
%pip install -qU langchain-text-splitters --quiet
from langchain_text_splitters import RecursiveCharacterTextSplitter
```
-```txt title="Output"
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m256.9/256.9 kB[0m [31m6.6 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m66.6/66.6 kB[0m [31m8.2 MB/s[0m eta [36m0:00:00[0m
-[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m138.5/138.5 kB[0m [31m14.5 MB/s[0m eta [36m0:00:00[0m
-[?25h
-```
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m256.9/256.9 kB[0m [31m6.6 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m66.6/66.6 kB[0m [31m8.2 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m138.5/138.5 kB[0m [31m14.5 MB/s[0m eta [36m0:00:00[0m
+ [?25h
-```python PYTHON
+
+```python
+# Create basic configurations to chunk the text
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
@@ -92,20 +103,22 @@ text_splitter = RecursiveCharacterTextSplitter(
is_separator_regex=False,
)
+# Split the text into chunks with some overlap
chunks_ = text_splitter.create_documents([text])
chunks = [c.page_content for c in chunks_]
print(f"The text has been broken down in {len(chunks)} chunks.")
```
-```txt title="Output"
-The text has been broken down in 91 chunks.
-```
+ The text has been broken down in 91 chunks.
+
### Embed every text chunk
Cohere embeddings are state-of-the-art.
-```python PYTHON
+
+```python
+# Because the texts being embedded are the chunks we are searching over, we set the input type as search_doc
model="embed-english-v3.0"
response = co.embed(
texts= chunks,
@@ -117,37 +130,46 @@ embeddings = response.embeddings.float
print(f"We just computed {len(embeddings)} embeddings.")
```
-```txt title="Output"
-We just computed 91 embeddings.
-```
+ We just computed 91 embeddings.
+
### Store the embeddings in a vector database
We use the simplest vector database ever: a python dictionary using `np.array()`.
-```python PYTHON
+
+```python
+# We use the simplest vector database ever: a python dictionary
!pip install numpy --quiet
```
-```python PYTHON
+
+```python
import numpy as np
vector_database = {i: np.array(embedding) for i, embedding in enumerate(embeddings)}
+# { 0: array([...]), 1: array([...]), 2: array([...]), ..., 10: array([...]) }
```
## Given a user query, retrieve the relevant chunks from the vector database
+
### Define the user question
-```python PYTHON
+
+```python
query = "Name everyone involved in writing the script, directing, and producing 'Dune: Part Two'?"
+# Note: the relevant passage in the wikipedia page we're looking for is:
+# "[...] Dune: Part Two was originally scheduled to be released on October 20, 2023, but was delayed to November 17, 2023, before moving forward two weeks to November 3, 2023, to adjust to changes in release schedules from other studios. It was later postponed by over four months to March 15, 2024, due to the 2023 Hollywood labor disputes. After the strikes were resolved, the film moved once more up two weeks to March 1, 2024. [...]"
```
### Embed the user question
Cohere embeddings are state-of-the-art.
-```python PYTHON
+
+```python
+# Because the text being embedded is the search query, we set the input type as search_query
response = co.embed(
texts=[query],
model=model,
@@ -158,47 +180,50 @@ query_embedding = response.embeddings.float[0]
print("query_embedding: ", query_embedding)
```
-```txt title="Output"
-query_embedding: [-0.068603516, -0.02947998, -0.06274414, -0.015449524, -0.033294678, 0.0056877136, -0.047210693, 0.04714966, -0.024871826, 0.008148193, 0.0770874, 0.023880005, -0.058685303, -0.052520752, 0.012832642, 0.024398804, 0.0053215027, 0.035491943, 0.02961731, -0.0069847107, 0.01083374, -0.0011358261, -0.002199173, 0.018417358, 0.027389526, -0.002691269, -0.026535034, 0.015197754, 0.024368286, 0.03729248, 0.0057754517, -0.02229309, -0.014694214, 0.019989014, -0.0036315918, -0.013793945, 0.02835083, 0.006011963, 0.011428833, 0.008682251, 0.046142578, -0.040039062, -0.032196045, -0.002653122, -0.012580872, -0.0041618347, 0.03111267, -0.016799927, 0.014801025, -0.00030636787, -0.033050537, 0.033966064, -0.016021729, -0.025009155, -0.007534027, -0.017074585, 0.008415222, -0.10620117, 0.019195557, -0.015686035, -0.0043182373, -0.045440674, 0.05404663, 0.030776978, -0.014129639, -0.01499939, -0.007286072, 0.009933472, 0.06390381, 0.02444458, -0.010345459, 0.041931152, 0.032989502, -0.04522705, 0.056610107, 0.0068893433, -0.008911133, 0.012489319, 0.01675415, 0.020065308, 0.018753052, 0.022659302, -0.051849365, -0.04925537, 0.046325684, -0.005268097, 0.0026874542, -0.036712646, 0.009437561, -0.0037841797, -0.01473999, -0.034179688, -0.0011606216, 0.05026245, 0.0020771027, -0.016021729, -0.0044898987, 0.04168701, -0.015205383, 0.019210815, -0.012374878, -0.031311035, 0.03111267, -0.040100098, -0.016479492, 0.020446777, 0.010192871, 0.0037841797, -0.0023765564, 0.015220642, -0.016571045, -0.006454468, 0.037384033, -0.044555664, -0.008262634, 0.019546509, 0.009460449, 0.014701843, 0.02658081, -0.02078247, 0.015571594, 0.013153076, -0.010375977, 0.047912598, 0.005393982, -0.007911682, -0.019378662, 0.023529053, -0.0033550262, -0.04598999, -0.0052871704, 0.040252686, 0.011375427, 0.01550293, -0.004508972, 0.006515503, 0.003370285, -0.022766113, 0.00062561035, -0.0007596016, -0.0015277863, 0.0149002075, 0.061401367, 8.261204e-05, 0.06359863, -0.01537323, 0.007446289, 0.018814087, 0.02507019, 0.024215698, 0.006122589, 0.005886078, -0.03829956, 0.029037476, 0.07720947, 0.016921997, 0.022109985, 0.005958557, 0.028793335, 0.019485474, 0.015174866, 0.026153564, 0.032318115, 0.034210205, 0.027145386, -0.019515991, -0.018661499, 0.020477295, 0.008598328, -0.06573486, -0.037109375, 0.04043579, 0.030471802, -0.0010843277, 0.009757996, 0.026947021, 0.037017822, -0.018234253, -0.0115356445, 0.099365234, 0.027816772, -0.019927979, 0.0020961761, 0.013198853, -0.019073486, 2.7656555e-05, 0.041259766, 0.029510498, -0.016204834, 0.028137207, 0.039489746, 0.034698486, -0.03918457, -0.029418945, 0.02041626, 0.0073432922, -0.018569946, -0.009849548, 0.002861023, 0.030319214, -0.012886047, 0.014671326, -0.035827637, 0.007247925, -0.027709961, -0.022079468, 0.0012960434, 0.015426636, -0.01725769, 0.01525116, 0.025360107, -0.0077400208, -0.039916992, 0.029037476, -0.011154175, 0.007736206, -0.041748047, 0.05343628, 0.007286072, 0.0435791, 0.034301758, -0.047210693, 0.03552246, -0.015327454, 0.029922485, -0.018859863, 0.013053894, -0.028060913, 0.07757568, -0.020462036, 0.070739746, -0.010223389, 0.03604126, 0.02758789, -0.023284912, 0.012184143, 0.029144287, 0.023880005, -0.019378662, -0.0051116943, 0.0048675537, 0.01864624, -0.04397583, -0.007598877, 0.0713501, 0.0115737915, 0.002922058, 0.011619568, 0.017364502, 0.031921387, -0.0019664764, -0.008575439, 0.003484726, -0.09466553, 0.03475952, 0.026611328, -0.039520264, -0.0104522705, -0.005443573, -0.008392334, 0.012908936, 0.0043792725, -0.002456665, -0.028396606, -0.02027893, -0.0005569458, 0.027786255, 0.03427124, -0.0062332153, -0.018203735, 0.019241333, 0.07244873, -0.0028057098, 0.01234436, -0.0018787384, -0.027496338, 0.0015287399, -0.004032135, -0.013748169, -0.01878357, 0.0018053055, -0.01159668, 0.028213501, 0.004776001, 0.042388916, 0.0024280548, 0.017471313, -0.038085938, 0.026321411, 0.02973938, 0.06213379, 0.006401062, 0.036102295, -0.028121948, -0.00869751, -0.016693115, 0.029190063, 0.016784668, -0.008628845, 0.0039634705, -0.0035381317, 0.019500732, 0.025009155, -0.04547119, -0.003572464, 0.05215454, 0.067871094, -0.04257202, -0.02293396, -0.027175903, 0.05340576, 0.019226074, 0.039978027, 0.056121826, -0.028320312, -0.020217896, -0.035003662, 0.03225708, 0.028656006, 0.062347412, 0.12915039, -0.0137786865, 0.0022201538, -0.057434082, -0.04397583, -0.049865723, -0.013160706, -0.03353882, 0.006427765, -0.014823914, -0.008201599, -0.036346436, -0.037353516, -0.010528564, -0.015930176, -0.027572632, 0.0074272156, 0.004547119, -0.024414062, -0.018859863, -0.020095825, 0.029632568, -0.00067043304, -0.044036865, -0.0043411255, -0.005256653, -0.019195557, 0.022262573, -0.00020956993, -0.013877869, -0.011108398, -0.020324707, -0.015808105, -0.025039673, -0.009498596, 0.05090332, 0.0046195984, -0.017150879, 0.04309082, -0.029067993, 0.002670288, -0.00026249886, -0.032409668, -0.053100586, 0.012481689, -0.014633179, 0.0013475418, -0.034332275, 0.038330078, 0.014892578, -0.046936035, 0.021591187, -0.020385742, -0.0052604675, 0.02796936, 0.0014333725, 0.012077332, -0.0118255615, -0.005569458, 0.008491516, 0.009841919, 0.0031318665, -0.003408432, -0.007144928, 0.040374756, -0.0038928986, 0.005279541, -0.008415222, 0.031707764, 0.0140686035, -0.015029907, -0.02810669, -0.0078125, -0.030853271, -0.03201294, 0.021316528, -0.036193848, -0.0423584, 0.0072784424, 0.014801025, 0.0019607544, -0.012367249, -0.009056091, -0.021438599, -0.02645874, 0.038726807, -0.007549286, 0.0049591064, 0.019012451, 0.017791748, -0.009185791, 0.04006958, 0.003107071, -0.0075302124, -0.010375977, -0.009246826, -0.02130127, -0.0056762695, -0.0076789856, 0.010009766, -0.010536194, 0.041107178, 0.0021133423, 0.029891968, 0.01626587, 0.042236328, -0.02784729, -0.032836914, 0.0317688, 0.045715332, 0.000116825104, 0.028030396, 0.007205963, 0.012512207, -0.035583496, -0.048034668, -0.023529053, -0.04953003, 0.0345459, -0.048339844, -0.060272217, -0.004512787, 0.04425049, 0.0076141357, 0.029510498, 0.007396698, 0.003353119, -0.038726807, 0.07183838, -0.026901245, -0.023529053, -0.038085938, 0.068725586, 0.018096924, -0.013534546, 0.05883789, -0.016113281, 0.017944336, 0.041046143, 0.022918701, 0.036499023, 0.015296936, -0.04916382, 0.0075683594, -0.011390686, 0.009735107, -0.0070152283, 0.003129959, -0.032562256, 0.0003478527, -0.0036640167, -0.006893158, -0.016098022, -0.034332275, 0.037750244, -0.010269165, 0.016494751, -0.02394104, 0.03753662, -0.022644043, -0.0008234978, 0.001001358, -0.048217773, 0.04989624, 0.0078125, 0.0044937134, 0.027038574, 0.04736328, -0.02973938, -0.011726379, 0.01348114, 0.021408081, 0.00844574, -0.03741455, -0.015686035, -0.040893555, 0.001452446, -0.025405884, 0.07348633, 0.038238525, -0.019958496, 0.023071289, -0.016403198, -0.08105469, 0.0071029663, -0.019088745, 5.8174133e-05, -0.005569458, 0.01399231, 0.02255249, 0.011222839, 0.00028824806, 0.0066184998, 0.0017499924, -0.009864807, -0.0115737915, 0.053100586, 0.0065231323, 0.001865387, -0.026428223, 0.03692627, 0.025390625, 0.022613525, 0.018722534, 0.007675171, -0.03439331, 0.041625977, -0.01789856, -0.041046143, 0.0051460266, 0.04144287, 0.048553467, 0.054595947, -0.01108551, -0.033935547, -0.026275635, -0.0118255615, -0.021362305, -0.009841919, -0.00724411, 0.028900146, 0.009887695, -0.023803711, 0.016311646, 0.018798828, -0.03668213, 0.046844482, 0.010696411, -0.014717102, -0.008110046, -0.004589081, -0.0028076172, -0.050811768, -0.017196655, -0.03491211, 0.0074005127, -0.038909912, 0.032440186, -0.034362793, -0.008682251, 0.032928467, -0.04626465, -0.009666443, 0.018951416, 0.031951904, -0.003791809, 0.02015686, -0.05532837, -0.005683899, -0.00054216385, -0.0034332275, 0.008659363, 0.02130127, -0.038879395, -0.0033397675, -0.03866577, -0.0049934387, 0.017944336, 0.001496315, 0.019485474, -0.004348755, 0.00046491623, 0.0007157326, 0.035614014, -0.027694702, 0.03692627, -0.008491516, 0.0524292, -0.016662598, -0.0017795563, -0.021575928, -0.018753052, -0.049346924, -0.06652832, 0.04272461, 0.03186035, 0.0011978149, 0.03463745, 0.024002075, 0.02607727, 0.020446777, 0.0256958, 0.026855469, 0.0074005127, -0.067993164, 0.017944336, -0.0039482117, 0.05496216, -0.041412354, 0.014175415, 0.02444458, -0.026412964, 0.057403564, -0.026779175, 0.023254395, 0.03945923, 0.033569336, -0.030258179, -0.039093018, -0.036468506, 0.017105103, 0.009635925, 0.025497437, 0.04156494, -0.02571106, -0.0010414124, -0.005630493, -0.016448975, -0.026733398, 0.001326561, -0.042022705, 0.0012521744, -0.041259766, -0.12182617, -0.03857422, 0.12548828, -0.005947113, -0.020736694, -0.0033855438, 0.03778076, -0.033813477, 0.038970947, 0.003921509, 0.011810303, 0.031982422, -0.032562256, -0.002653122, -0.025009155, -0.03805542, -0.016998291, 0.018173218, 0.0158844, 0.0011739731, 0.048217773, -0.020401001, 0.044708252, -0.017318726, 0.014457703, -0.041809082, 0.010543823, 0.041931152, 0.076293945, -0.054779053, 0.060272217, -0.046936035, 0.02949524, 0.00554657, 0.041534424, -0.013046265, -0.056152344, 0.010406494, 0.02973938, -0.023727417, -0.022476196, -0.024734497, -0.013168335, 0.060424805, 0.011787415, 0.018997192, -0.043426514, -0.00077724457, -0.010154724, 0.017150879, -0.01171875, -0.022476196, 0.0034255981, -0.0026454926, 0.004837036, -0.0043296814, 0.02619934, -0.021560669, -0.039733887, -0.022415161, -0.06817627, -0.023223877, -0.018585205, -0.015319824, 0.012588501, 0.0064353943, -0.013748169, 0.043304443, 0.002626419, -0.029373169, -0.016784668, -0.026184082, 0.05847168, 0.034179688, 0.03842163, -0.05493164, -0.017486572, 0.016540527, 0.03164673, 0.089904785, 0.013534546, -0.07684326, -0.024108887, 0.07434082, 0.030395508, 0.007091522, 0.07373047, 0.012527466, -0.010856628, -0.01828003, -0.045196533, 0.00065279007, -0.0637207, 0.010726929, 0.023880005, -0.0030708313, -0.012298584, 0.027236938, -0.04928589, 0.023071289, 0.008674622, -0.023529053, -0.015838623, -0.010543823, 0.012168884, 0.014854431, -0.05834961, -0.06088257, -0.012313843, 0.035461426, 0.02027893, 0.019348145, -0.014602661, -0.02104187, -0.0309906, 0.001405716, -0.019973755, -0.00157547, -0.003944397, 0.0009326935, -0.02078247, -0.015731812, -0.044433594, 0.03390503, 0.057159424, 0.018585205, -0.023895264, -0.0057029724, 0.0049552917, 0.013412476, 0.022399902, 0.010154724, 0.0519104, 0.06591797, 0.018341064, 0.012161255, -0.05810547, -0.043304443, -0.031173706, 0.0023860931, -0.003944397, 0.11425781, -0.031036377, 0.019989014, -0.038635254, -0.025939941, 0.035064697, 0.041168213, 0.03161621, -0.069885254, -0.04537964, 0.028945923, -0.023162842, 0.019226074, -0.028442383, 0.015594482, -0.019256592, -0.0046463013, 0.034240723, 0.009124756, 0.05718994, 0.031219482, 0.02154541, 0.009590149, 0.00076818466, 0.04849243, -0.029129028, -0.03375244, -0.023391724, -0.028381348, -0.029708862, -0.0132369995, 0.010353088, 0.020263672, -0.030807495, 0.01007843, -0.03704834, 0.023376465, -0.03665161, 0.03741455, 0.015144348, 0.057281494, 0.03137207, 0.048431396, 0.021194458, 0.008110046, -0.03540039, -0.015312195, 0.022384644, 0.0065956116, 0.008056641, 0.0018348694, -0.009246826, 0.030380249, 0.0003862381, 0.0051841736, 0.04486084, 0.017807007, 0.0026130676, 0.07977295, 0.05419922, 0.062194824, 0.02633667, 0.024841309, -0.041625977, -0.005897522, 0.04031372, -0.055908203, 0.0026226044, -0.05340576, -0.05496216, 0.011474609, -0.006954193, -0.013122559, 0.019714355, -0.07159424, 0.031173706, 0.0034255981, -0.0034103394, 0.0440979, 0.011779785, -0.007827759, -0.03173828, -0.020950317, -0.030166626, -0.035308838, 0.030792236, 0.04525757, -0.028701782, -0.011100769, -0.02331543, -0.0357666, -0.025680542, 0.0011911392, 0.01940918, 0.05706787, 0.028381348, 0.007133484, -0.07733154, -0.007686615, 0.03869629, 0.0066833496, 0.008842468, 0.03439331, -0.014282227, 0.0357666, -0.004737854, -0.039794922, -0.0070381165, 0.02670288, 0.0107421875, 0.016189575, -0.06555176, -0.0138549805, 0.0008363724, -0.016693115, 0.006904602, -0.020263672, -0.030426025, 0.008453369, -0.046173096, -0.01802063, -0.013595581, -0.0044288635, -0.0039978027, -0.0044898987, 0.0007619858, 0.003921509, 0.0053977966, 0.020385742, -0.012329102, -0.023803711, -0.0057525635, 0.038330078, -0.014549255, -0.06298828, -0.047607422, 0.039245605, -0.06781006, -0.035217285, -0.009056091, 0.019927979, -0.003932953, -0.020309448, -0.017044067, 0.018127441, -8.624792e-05, -0.043182373, 0.009590149, 0.035308838, 0.031951904, 0.0011615753, -0.042022705, 0.079956055, 0.026687622, 0.013542175, -0.0074157715, -0.00983429, -0.0022563934, 0.07373047, 0.059387207, 0.03488159, 0.0071372986, -0.06427002, -0.0546875, -0.02482605, 0.11071777, -0.021072388, 0.01626587, -0.049713135, 0.061553955, -0.016860962, 0.051971436, -0.012962341, -0.0011711121, -0.014198303, -0.0061149597, -0.005836487, 0.00022387505, -0.027618408, 0.019836426, 0.009933472, 0.02368164, -0.020309448, -0.0049591064, -0.008628845, -0.03253174, -0.017684937, 0.02468872, -0.0023498535, 0.01448822, 0.061920166, 0.031707764, -0.0026416779, -0.040985107, -0.06335449, -0.036071777, 0.05404663, -0.0044136047, -0.0146102905, -0.0033416748, 0.028671265, -0.012771606, -0.0016565323, -0.0038909912, -0.02407837, -0.009857178, 0.0014467239, -0.008720398, -0.006011963, 0.032073975, -0.033325195, 0.014862061, -0.017227173, -0.018753052, -0.0060424805, 0.022567749, -0.017654419, -0.017562866, -0.07244873, -0.0881958, 0.050476074, 0.02609253, -0.032409668, 0.07458496, 0.009399414, 0.009117126, -0.031051636, -0.03451538, -0.004219055, -0.05718994, 0.020080566, -0.025421143, -0.010948181, 0.06341553, -0.009231567, -0.021697998, -0.009719849, 0.012802124, -0.020370483, 0.0034389496, 0.018859863, -0.025680542, 0.0013141632, 0.068603516, -0.021026611, 0.021881104, -0.0395813, -0.0019073486, 0.0056037903, -0.032348633]
-```
+ query_embedding: [-0.068603516, -0.02947998, -0.06274414, -0.015449524, -0.033294678, 0.0056877136, -0.047210693, 0.04714966, -0.024871826, 0.008148193, 0.0770874, 0.023880005, -0.058685303, -0.052520752, 0.012832642, 0.024398804, 0.0053215027, 0.035491943, 0.02961731, -0.0069847107, 0.01083374, -0.0011358261, -0.002199173, 0.018417358, 0.027389526, -0.002691269, -0.026535034, 0.015197754, 0.024368286, 0.03729248, 0.0057754517, -0.02229309, -0.014694214, 0.019989014, -0.0036315918, -0.013793945, 0.02835083, 0.006011963, 0.011428833, 0.008682251, 0.046142578, -0.040039062, -0.032196045, -0.002653122, -0.012580872, -0.0041618347, 0.03111267, -0.016799927, 0.014801025, -0.00030636787, -0.033050537, 0.033966064, -0.016021729, -0.025009155, -0.007534027, -0.017074585, 0.008415222, -0.10620117, 0.019195557, -0.015686035, -0.0043182373, -0.045440674, 0.05404663, 0.030776978, -0.014129639, -0.01499939, -0.007286072, 0.009933472, 0.06390381, 0.02444458, -0.010345459, 0.041931152, 0.032989502, -0.04522705, 0.056610107, 0.0068893433, -0.008911133, 0.012489319, 0.01675415, 0.020065308, 0.018753052, 0.022659302, -0.051849365, -0.04925537, 0.046325684, -0.005268097, 0.0026874542, -0.036712646, 0.009437561, -0.0037841797, -0.01473999, -0.034179688, -0.0011606216, 0.05026245, 0.0020771027, -0.016021729, -0.0044898987, 0.04168701, -0.015205383, 0.019210815, -0.012374878, -0.031311035, 0.03111267, -0.040100098, -0.016479492, 0.020446777, 0.010192871, 0.0037841797, -0.0023765564, 0.015220642, -0.016571045, -0.006454468, 0.037384033, -0.044555664, -0.008262634, 0.019546509, 0.009460449, 0.014701843, 0.02658081, -0.02078247, 0.015571594, 0.013153076, -0.010375977, 0.047912598, 0.005393982, -0.007911682, -0.019378662, 0.023529053, -0.0033550262, -0.04598999, -0.0052871704, 0.040252686, 0.011375427, 0.01550293, -0.004508972, 0.006515503, 0.003370285, -0.022766113, 0.00062561035, -0.0007596016, -0.0015277863, 0.0149002075, 0.061401367, 8.261204e-05, 0.06359863, -0.01537323, 0.007446289, 0.018814087, 0.02507019, 0.024215698, 0.006122589, 0.005886078, -0.03829956, 0.029037476, 0.07720947, 0.016921997, 0.022109985, 0.005958557, 0.028793335, 0.019485474, 0.015174866, 0.026153564, 0.032318115, 0.034210205, 0.027145386, -0.019515991, -0.018661499, 0.020477295, 0.008598328, -0.06573486, -0.037109375, 0.04043579, 0.030471802, -0.0010843277, 0.009757996, 0.026947021, 0.037017822, -0.018234253, -0.0115356445, 0.099365234, 0.027816772, -0.019927979, 0.0020961761, 0.013198853, -0.019073486, 2.7656555e-05, 0.041259766, 0.029510498, -0.016204834, 0.028137207, 0.039489746, 0.034698486, -0.03918457, -0.029418945, 0.02041626, 0.0073432922, -0.018569946, -0.009849548, 0.002861023, 0.030319214, -0.012886047, 0.014671326, -0.035827637, 0.007247925, -0.027709961, -0.022079468, 0.0012960434, 0.015426636, -0.01725769, 0.01525116, 0.025360107, -0.0077400208, -0.039916992, 0.029037476, -0.011154175, 0.007736206, -0.041748047, 0.05343628, 0.007286072, 0.0435791, 0.034301758, -0.047210693, 0.03552246, -0.015327454, 0.029922485, -0.018859863, 0.013053894, -0.028060913, 0.07757568, -0.020462036, 0.070739746, -0.010223389, 0.03604126, 0.02758789, -0.023284912, 0.012184143, 0.029144287, 0.023880005, -0.019378662, -0.0051116943, 0.0048675537, 0.01864624, -0.04397583, -0.007598877, 0.0713501, 0.0115737915, 0.002922058, 0.011619568, 0.017364502, 0.031921387, -0.0019664764, -0.008575439, 0.003484726, -0.09466553, 0.03475952, 0.026611328, -0.039520264, -0.0104522705, -0.005443573, -0.008392334, 0.012908936, 0.0043792725, -0.002456665, -0.028396606, -0.02027893, -0.0005569458, 0.027786255, 0.03427124, -0.0062332153, -0.018203735, 0.019241333, 0.07244873, -0.0028057098, 0.01234436, -0.0018787384, -0.027496338, 0.0015287399, -0.004032135, -0.013748169, -0.01878357, 0.0018053055, -0.01159668, 0.028213501, 0.004776001, 0.042388916, 0.0024280548, 0.017471313, -0.038085938, 0.026321411, 0.02973938, 0.06213379, 0.006401062, 0.036102295, -0.028121948, -0.00869751, -0.016693115, 0.029190063, 0.016784668, -0.008628845, 0.0039634705, -0.0035381317, 0.019500732, 0.025009155, -0.04547119, -0.003572464, 0.05215454, 0.067871094, -0.04257202, -0.02293396, -0.027175903, 0.05340576, 0.019226074, 0.039978027, 0.056121826, -0.028320312, -0.020217896, -0.035003662, 0.03225708, 0.028656006, 0.062347412, 0.12915039, -0.0137786865, 0.0022201538, -0.057434082, -0.04397583, -0.049865723, -0.013160706, -0.03353882, 0.006427765, -0.014823914, -0.008201599, -0.036346436, -0.037353516, -0.010528564, -0.015930176, -0.027572632, 0.0074272156, 0.004547119, -0.024414062, -0.018859863, -0.020095825, 0.029632568, -0.00067043304, -0.044036865, -0.0043411255, -0.005256653, -0.019195557, 0.022262573, -0.00020956993, -0.013877869, -0.011108398, -0.020324707, -0.015808105, -0.025039673, -0.009498596, 0.05090332, 0.0046195984, -0.017150879, 0.04309082, -0.029067993, 0.002670288, -0.00026249886, -0.032409668, -0.053100586, 0.012481689, -0.014633179, 0.0013475418, -0.034332275, 0.038330078, 0.014892578, -0.046936035, 0.021591187, -0.020385742, -0.0052604675, 0.02796936, 0.0014333725, 0.012077332, -0.0118255615, -0.005569458, 0.008491516, 0.009841919, 0.0031318665, -0.003408432, -0.007144928, 0.040374756, -0.0038928986, 0.005279541, -0.008415222, 0.031707764, 0.0140686035, -0.015029907, -0.02810669, -0.0078125, -0.030853271, -0.03201294, 0.021316528, -0.036193848, -0.0423584, 0.0072784424, 0.014801025, 0.0019607544, -0.012367249, -0.009056091, -0.021438599, -0.02645874, 0.038726807, -0.007549286, 0.0049591064, 0.019012451, 0.017791748, -0.009185791, 0.04006958, 0.003107071, -0.0075302124, -0.010375977, -0.009246826, -0.02130127, -0.0056762695, -0.0076789856, 0.010009766, -0.010536194, 0.041107178, 0.0021133423, 0.029891968, 0.01626587, 0.042236328, -0.02784729, -0.032836914, 0.0317688, 0.045715332, 0.000116825104, 0.028030396, 0.007205963, 0.012512207, -0.035583496, -0.048034668, -0.023529053, -0.04953003, 0.0345459, -0.048339844, -0.060272217, -0.004512787, 0.04425049, 0.0076141357, 0.029510498, 0.007396698, 0.003353119, -0.038726807, 0.07183838, -0.026901245, -0.023529053, -0.038085938, 0.068725586, 0.018096924, -0.013534546, 0.05883789, -0.016113281, 0.017944336, 0.041046143, 0.022918701, 0.036499023, 0.015296936, -0.04916382, 0.0075683594, -0.011390686, 0.009735107, -0.0070152283, 0.003129959, -0.032562256, 0.0003478527, -0.0036640167, -0.006893158, -0.016098022, -0.034332275, 0.037750244, -0.010269165, 0.016494751, -0.02394104, 0.03753662, -0.022644043, -0.0008234978, 0.001001358, -0.048217773, 0.04989624, 0.0078125, 0.0044937134, 0.027038574, 0.04736328, -0.02973938, -0.011726379, 0.01348114, 0.021408081, 0.00844574, -0.03741455, -0.015686035, -0.040893555, 0.001452446, -0.025405884, 0.07348633, 0.038238525, -0.019958496, 0.023071289, -0.016403198, -0.08105469, 0.0071029663, -0.019088745, 5.8174133e-05, -0.005569458, 0.01399231, 0.02255249, 0.011222839, 0.00028824806, 0.0066184998, 0.0017499924, -0.009864807, -0.0115737915, 0.053100586, 0.0065231323, 0.001865387, -0.026428223, 0.03692627, 0.025390625, 0.022613525, 0.018722534, 0.007675171, -0.03439331, 0.041625977, -0.01789856, -0.041046143, 0.0051460266, 0.04144287, 0.048553467, 0.054595947, -0.01108551, -0.033935547, -0.026275635, -0.0118255615, -0.021362305, -0.009841919, -0.00724411, 0.028900146, 0.009887695, -0.023803711, 0.016311646, 0.018798828, -0.03668213, 0.046844482, 0.010696411, -0.014717102, -0.008110046, -0.004589081, -0.0028076172, -0.050811768, -0.017196655, -0.03491211, 0.0074005127, -0.038909912, 0.032440186, -0.034362793, -0.008682251, 0.032928467, -0.04626465, -0.009666443, 0.018951416, 0.031951904, -0.003791809, 0.02015686, -0.05532837, -0.005683899, -0.00054216385, -0.0034332275, 0.008659363, 0.02130127, -0.038879395, -0.0033397675, -0.03866577, -0.0049934387, 0.017944336, 0.001496315, 0.019485474, -0.004348755, 0.00046491623, 0.0007157326, 0.035614014, -0.027694702, 0.03692627, -0.008491516, 0.0524292, -0.016662598, -0.0017795563, -0.021575928, -0.018753052, -0.049346924, -0.06652832, 0.04272461, 0.03186035, 0.0011978149, 0.03463745, 0.024002075, 0.02607727, 0.020446777, 0.0256958, 0.026855469, 0.0074005127, -0.067993164, 0.017944336, -0.0039482117, 0.05496216, -0.041412354, 0.014175415, 0.02444458, -0.026412964, 0.057403564, -0.026779175, 0.023254395, 0.03945923, 0.033569336, -0.030258179, -0.039093018, -0.036468506, 0.017105103, 0.009635925, 0.025497437, 0.04156494, -0.02571106, -0.0010414124, -0.005630493, -0.016448975, -0.026733398, 0.001326561, -0.042022705, 0.0012521744, -0.041259766, -0.12182617, -0.03857422, 0.12548828, -0.005947113, -0.020736694, -0.0033855438, 0.03778076, -0.033813477, 0.038970947, 0.003921509, 0.011810303, 0.031982422, -0.032562256, -0.002653122, -0.025009155, -0.03805542, -0.016998291, 0.018173218, 0.0158844, 0.0011739731, 0.048217773, -0.020401001, 0.044708252, -0.017318726, 0.014457703, -0.041809082, 0.010543823, 0.041931152, 0.076293945, -0.054779053, 0.060272217, -0.046936035, 0.02949524, 0.00554657, 0.041534424, -0.013046265, -0.056152344, 0.010406494, 0.02973938, -0.023727417, -0.022476196, -0.024734497, -0.013168335, 0.060424805, 0.011787415, 0.018997192, -0.043426514, -0.00077724457, -0.010154724, 0.017150879, -0.01171875, -0.022476196, 0.0034255981, -0.0026454926, 0.004837036, -0.0043296814, 0.02619934, -0.021560669, -0.039733887, -0.022415161, -0.06817627, -0.023223877, -0.018585205, -0.015319824, 0.012588501, 0.0064353943, -0.013748169, 0.043304443, 0.002626419, -0.029373169, -0.016784668, -0.026184082, 0.05847168, 0.034179688, 0.03842163, -0.05493164, -0.017486572, 0.016540527, 0.03164673, 0.089904785, 0.013534546, -0.07684326, -0.024108887, 0.07434082, 0.030395508, 0.007091522, 0.07373047, 0.012527466, -0.010856628, -0.01828003, -0.045196533, 0.00065279007, -0.0637207, 0.010726929, 0.023880005, -0.0030708313, -0.012298584, 0.027236938, -0.04928589, 0.023071289, 0.008674622, -0.023529053, -0.015838623, -0.010543823, 0.012168884, 0.014854431, -0.05834961, -0.06088257, -0.012313843, 0.035461426, 0.02027893, 0.019348145, -0.014602661, -0.02104187, -0.0309906, 0.001405716, -0.019973755, -0.00157547, -0.003944397, 0.0009326935, -0.02078247, -0.015731812, -0.044433594, 0.03390503, 0.057159424, 0.018585205, -0.023895264, -0.0057029724, 0.0049552917, 0.013412476, 0.022399902, 0.010154724, 0.0519104, 0.06591797, 0.018341064, 0.012161255, -0.05810547, -0.043304443, -0.031173706, 0.0023860931, -0.003944397, 0.11425781, -0.031036377, 0.019989014, -0.038635254, -0.025939941, 0.035064697, 0.041168213, 0.03161621, -0.069885254, -0.04537964, 0.028945923, -0.023162842, 0.019226074, -0.028442383, 0.015594482, -0.019256592, -0.0046463013, 0.034240723, 0.009124756, 0.05718994, 0.031219482, 0.02154541, 0.009590149, 0.00076818466, 0.04849243, -0.029129028, -0.03375244, -0.023391724, -0.028381348, -0.029708862, -0.0132369995, 0.010353088, 0.020263672, -0.030807495, 0.01007843, -0.03704834, 0.023376465, -0.03665161, 0.03741455, 0.015144348, 0.057281494, 0.03137207, 0.048431396, 0.021194458, 0.008110046, -0.03540039, -0.015312195, 0.022384644, 0.0065956116, 0.008056641, 0.0018348694, -0.009246826, 0.030380249, 0.0003862381, 0.0051841736, 0.04486084, 0.017807007, 0.0026130676, 0.07977295, 0.05419922, 0.062194824, 0.02633667, 0.024841309, -0.041625977, -0.005897522, 0.04031372, -0.055908203, 0.0026226044, -0.05340576, -0.05496216, 0.011474609, -0.006954193, -0.013122559, 0.019714355, -0.07159424, 0.031173706, 0.0034255981, -0.0034103394, 0.0440979, 0.011779785, -0.007827759, -0.03173828, -0.020950317, -0.030166626, -0.035308838, 0.030792236, 0.04525757, -0.028701782, -0.011100769, -0.02331543, -0.0357666, -0.025680542, 0.0011911392, 0.01940918, 0.05706787, 0.028381348, 0.007133484, -0.07733154, -0.007686615, 0.03869629, 0.0066833496, 0.008842468, 0.03439331, -0.014282227, 0.0357666, -0.004737854, -0.039794922, -0.0070381165, 0.02670288, 0.0107421875, 0.016189575, -0.06555176, -0.0138549805, 0.0008363724, -0.016693115, 0.006904602, -0.020263672, -0.030426025, 0.008453369, -0.046173096, -0.01802063, -0.013595581, -0.0044288635, -0.0039978027, -0.0044898987, 0.0007619858, 0.003921509, 0.0053977966, 0.020385742, -0.012329102, -0.023803711, -0.0057525635, 0.038330078, -0.014549255, -0.06298828, -0.047607422, 0.039245605, -0.06781006, -0.035217285, -0.009056091, 0.019927979, -0.003932953, -0.020309448, -0.017044067, 0.018127441, -8.624792e-05, -0.043182373, 0.009590149, 0.035308838, 0.031951904, 0.0011615753, -0.042022705, 0.079956055, 0.026687622, 0.013542175, -0.0074157715, -0.00983429, -0.0022563934, 0.07373047, 0.059387207, 0.03488159, 0.0071372986, -0.06427002, -0.0546875, -0.02482605, 0.11071777, -0.021072388, 0.01626587, -0.049713135, 0.061553955, -0.016860962, 0.051971436, -0.012962341, -0.0011711121, -0.014198303, -0.0061149597, -0.005836487, 0.00022387505, -0.027618408, 0.019836426, 0.009933472, 0.02368164, -0.020309448, -0.0049591064, -0.008628845, -0.03253174, -0.017684937, 0.02468872, -0.0023498535, 0.01448822, 0.061920166, 0.031707764, -0.0026416779, -0.040985107, -0.06335449, -0.036071777, 0.05404663, -0.0044136047, -0.0146102905, -0.0033416748, 0.028671265, -0.012771606, -0.0016565323, -0.0038909912, -0.02407837, -0.009857178, 0.0014467239, -0.008720398, -0.006011963, 0.032073975, -0.033325195, 0.014862061, -0.017227173, -0.018753052, -0.0060424805, 0.022567749, -0.017654419, -0.017562866, -0.07244873, -0.0881958, 0.050476074, 0.02609253, -0.032409668, 0.07458496, 0.009399414, 0.009117126, -0.031051636, -0.03451538, -0.004219055, -0.05718994, 0.020080566, -0.025421143, -0.010948181, 0.06341553, -0.009231567, -0.021697998, -0.009719849, 0.012802124, -0.020370483, 0.0034389496, 0.018859863, -0.025680542, 0.0013141632, 0.068603516, -0.021026611, 0.021881104, -0.0395813, -0.0019073486, 0.0056037903, -0.032348633]
+
### Retrieve the most relevant chunks from the vector database
We use cosine similarity to find the most similar chunks
-```python PYTHON
+
+```python
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
+# Calculate similarity between the user question & each chunk
similarities = [cosine_similarity(query_embedding, chunk) for chunk in embeddings]
print("similarity scores: ", similarities)
+# Get indices of the top 10 most similar chunks
sorted_indices = np.argsort(similarities)[::-1]
+# Keep only the top 10 indices
top_indices = sorted_indices[:10]
print("Here are the indices of the top 10 chunks after retrieval: ", top_indices)
+# Retrieve the top 10 most similar chunks
top_chunks_after_retrieval = [chunks[i] for i in top_indices]
print("Here are the top 10 chunks after retrieval: ")
for t in top_chunks_after_retrieval:
print("== " + t)
```
-```txt title="Output"
-similarity scores: [0.6953257882233425, 0.3713410510180273, 0.46501499776898964, 0.5448546916785195, 0.4014738351361969, 0.3231420292334584, 0.3179003053384008, 0.42799691553367775, 0.18882594531435784, 0.36868801306504106, 0.3404040737300553, 0.3852837621219358, 0.2600249419491577, 0.3723244353775111, 0.3631492691137214, 0.47574774051439606, 0.40415422750911745, 0.4149923346201023, 0.5014741934381444, 0.3549433331883204, 0.32072714802512714, 0.14770872479410424, 0.585277816615252, 0.6999636953772764, 0.7722295084104617, 0.4895347049465806, 0.5170096485954725, 0.7137817366881455, 0.5224900699612323, 0.5914632581598285, 0.2657897083381463, 0.6462342489537262, 0.6317222315431096, 0.5982303530756702, 0.5138265091630297, 0.41385121172723643, 0.4293941094100836, 0.4173182546482015, 0.42621236706314475, 0.4428474375355954, 0.35058541576139896, 0.3578709652019502, 0.3930157841938308, 0.3564608202848675, 0.23016661533167404, 0.4933441863421645, 0.41037089239250985, 0.39993051898770193, 0.3119997063424595, 0.2677143729521374, 0.3700866951454496, 0.46727994925061545, 0.4393343280374425, 0.42111290117172434, 0.4485349189824285, 0.4710573736688592, 0.24169956903740436, 0.3840442910806355, 0.14284631817675886, 0.5381588054138154, 0.431113882725076, 0.5189547209048608, 0.3950667224233914, 0.32429768756510174, 0.4370358125161736, 0.18727062244331039, 0.5206375682478743, 0.5175737635701252, 0.5326043981628349, 0.45586923626994363, 0.21667338125532032, 0.16459878595959285, 0.22236726481673777, 0.5187259906958807, 0.2884444442338396, 0.286407544555338, 0.2313840178160818, 0.2057731158935257, 0.5973876998341746, 0.42904243401792086, 0.4081217538000544, 0.5330523063972133, 0.45080561486977405, 0.414703452285757, 0.2569028899107211, 0.5087916806929323, 0.14159076456040554, 0.46505779053352697, 0.556364222182839, 0.35464351181035236, 0.40174477023626]
-Here are the indices of the top 10 chunks after retrieval: [24 27 23 0 31 32 33 78 29 22]
-Here are the top 10 chunks after retrieval:
-== stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,
-== that."On October 26, 2021, Legendary officially greenlit Dune: Part Two, with a spokesperson for the company stating, "We would not have gotten to this point without the extraordinary vision of Denis and the amazing work of his talented crew, the writers, our stellar cast, our partners at Warner Bros., and of course the fans! Here's to more Dune." Production work had occurred back-to-back with the first film, as Villeneuve and his wife Lapointe immediately took a flight to Budapest in order to begin
-== series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by
-== Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first
-== Eric Roth was hired to co-write the screenplay in April 2017 for the Dune films, and Jon Spaihts was later confirmed to be co-writing the script alongside Roth and Villeneuve. Game of Thrones language creator David Peterson was confirmed to be developing languages for the film in April 2019. Villeneuve and Peterson had created the Chakobsa language, which was used by actors on set. In November 2019, Spaihts stepped down as showrunner for Dune: Prophecy to focus on Dune: Part Two. In June 2020, Greig Fraser
-== on Dune: Part Two. In June 2020, Greig Fraser said, "It's a fully formed story in itself with places to go. It's a fully standalone epic film that people will get a lot out of when they see it". Between the release of Dune and the confirmation of Dune: Part Two, Villeneuve started working the script in a way that production could begin immediately once the film was greenlit. By February 2021, Roth created a full treatment for the sequel, with writing beginning that August. He confirmed that Feyd-Rautha
-== that August. He confirmed that Feyd-Rautha would appear in the film, and stated he will be a "very important character". In March 2022, Villeneuve had mostly finished writing the screenplay. Craig Mazin and Roth wrote additional literary material for the film.Villeneuve stated that the film would continue directly from the first, and specifically described it as being the "second part." He described the film as being an "epic war movie", adding that while the first film was more "contemplative", the second
-== On the review aggregator website Rotten Tomatoes, 93% of 378 critics' reviews are positive, with an average rating of 8.4/10. The website's consensus reads: "Visually thrilling and narratively epic, Dune: Part Two continues Denis Villeneuve's adaptation of the beloved sci-fi series in spectacular form." Metacritic, which uses a weighted average, assigned the film a score of 79 out of 100, based on 62 critics, indicating "generally favorable" reviews. Audiences surveyed by CinemaScore gave the film an
-== theatrical experience is at the very heart of the cinematic language for me." With Dune: Part Two being greenlit, Villeneuve said that his primary concern was to complete the filming as soon as possible, with the earliest he expected to start in the last quarter of 2022. However, he noted that production would be facilitated by the work already established on the first film, which would help expedite production.
-== By November 2016, Legendary Pictures had obtained the film and TV rights for the Dune franchise, based on the eponymous 1965 novel by Frank Herbert. Vice chair of worldwide production for Legendary Mary Parent began discussing with Denis Villeneuve about directing a film adaptation, quickly hiring him after realizing his passion for Dune. By February 2018, Villeneuve was confirmed to be hired as director, and intended to adapt the novel as a two-part film series. Villeneuve ultimately secured a two-film
-```
+ similarity scores: [0.6953257882233425, 0.3713410510180273, 0.46501499776898964, 0.5448546916785195, 0.4014738351361969, 0.3231420292334584, 0.3179003053384008, 0.42799691553367775, 0.18882594531435784, 0.36868801306504106, 0.3404040737300553, 0.3852837621219358, 0.2600249419491577, 0.3723244353775111, 0.3631492691137214, 0.47574774051439606, 0.40415422750911745, 0.4149923346201023, 0.5014741934381444, 0.3549433331883204, 0.32072714802512714, 0.14770872479410424, 0.585277816615252, 0.6999636953772764, 0.7722295084104617, 0.4895347049465806, 0.5170096485954725, 0.7137817366881455, 0.5224900699612323, 0.5914632581598285, 0.2657897083381463, 0.6462342489537262, 0.6317222315431096, 0.5982303530756702, 0.5138265091630297, 0.41385121172723643, 0.4293941094100836, 0.4173182546482015, 0.42621236706314475, 0.4428474375355954, 0.35058541576139896, 0.3578709652019502, 0.3930157841938308, 0.3564608202848675, 0.23016661533167404, 0.4933441863421645, 0.41037089239250985, 0.39993051898770193, 0.3119997063424595, 0.2677143729521374, 0.3700866951454496, 0.46727994925061545, 0.4393343280374425, 0.42111290117172434, 0.4485349189824285, 0.4710573736688592, 0.24169956903740436, 0.3840442910806355, 0.14284631817675886, 0.5381588054138154, 0.431113882725076, 0.5189547209048608, 0.3950667224233914, 0.32429768756510174, 0.4370358125161736, 0.18727062244331039, 0.5206375682478743, 0.5175737635701252, 0.5326043981628349, 0.45586923626994363, 0.21667338125532032, 0.16459878595959285, 0.22236726481673777, 0.5187259906958807, 0.2884444442338396, 0.286407544555338, 0.2313840178160818, 0.2057731158935257, 0.5973876998341746, 0.42904243401792086, 0.4081217538000544, 0.5330523063972133, 0.45080561486977405, 0.414703452285757, 0.2569028899107211, 0.5087916806929323, 0.14159076456040554, 0.46505779053352697, 0.556364222182839, 0.35464351181035236, 0.40174477023626]
+ Here are the indices of the top 10 chunks after retrieval: [24 27 23 0 31 32 33 78 29 22]
+ Here are the top 10 chunks after retrieval:
+ == stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,
+ == that."On October 26, 2021, Legendary officially greenlit Dune: Part Two, with a spokesperson for the company stating, "We would not have gotten to this point without the extraordinary vision of Denis and the amazing work of his talented crew, the writers, our stellar cast, our partners at Warner Bros., and of course the fans! Here's to more Dune." Production work had occurred back-to-back with the first film, as Villeneuve and his wife Lapointe immediately took a flight to Budapest in order to begin
+ == series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by
+ == Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first
+ == Eric Roth was hired to co-write the screenplay in April 2017 for the Dune films, and Jon Spaihts was later confirmed to be co-writing the script alongside Roth and Villeneuve. Game of Thrones language creator David Peterson was confirmed to be developing languages for the film in April 2019. Villeneuve and Peterson had created the Chakobsa language, which was used by actors on set. In November 2019, Spaihts stepped down as showrunner for Dune: Prophecy to focus on Dune: Part Two. In June 2020, Greig Fraser
+ == on Dune: Part Two. In June 2020, Greig Fraser said, "It's a fully formed story in itself with places to go. It's a fully standalone epic film that people will get a lot out of when they see it". Between the release of Dune and the confirmation of Dune: Part Two, Villeneuve started working the script in a way that production could begin immediately once the film was greenlit. By February 2021, Roth created a full treatment for the sequel, with writing beginning that August. He confirmed that Feyd-Rautha
+ == that August. He confirmed that Feyd-Rautha would appear in the film, and stated he will be a "very important character". In March 2022, Villeneuve had mostly finished writing the screenplay. Craig Mazin and Roth wrote additional literary material for the film.Villeneuve stated that the film would continue directly from the first, and specifically described it as being the "second part." He described the film as being an "epic war movie", adding that while the first film was more "contemplative", the second
+ == On the review aggregator website Rotten Tomatoes, 93% of 378 critics' reviews are positive, with an average rating of 8.4/10. The website's consensus reads: "Visually thrilling and narratively epic, Dune: Part Two continues Denis Villeneuve's adaptation of the beloved sci-fi series in spectacular form." Metacritic, which uses a weighted average, assigned the film a score of 79 out of 100, based on 62 critics, indicating "generally favorable" reviews. Audiences surveyed by CinemaScore gave the film an
+ == theatrical experience is at the very heart of the cinematic language for me." With Dune: Part Two being greenlit, Villeneuve said that his primary concern was to complete the filming as soon as possible, with the earliest he expected to start in the last quarter of 2022. However, he noted that production would be facilitated by the work already established on the first film, which would help expedite production.
+ == By November 2016, Legendary Pictures had obtained the film and TV rights for the Dune franchise, based on the eponymous 1965 novel by Frank Herbert. Vice chair of worldwide production for Legendary Mary Parent began discussing with Denis Villeneuve about directing a film adaptation, quickly hiring him after realizing his passion for Dune. By February 2018, Villeneuve was confirmed to be hired as director, and intended to adapt the novel as a two-part film series. Villeneuve ultimately secured a two-film
+
## Step 2 - Rerank the chunks retrieved from the vector database
@@ -206,7 +231,8 @@ We rerank the 10 chunks retrieved from the vector database. Reranking boosts ret
Reranking lets us go from 10 chunks retrieved from the vector database, to the 3 most relevant chunks.
-```python PYTHON
+
+```python
response = co.rerank(
query=query,
documents=top_chunks_after_retrieval,
@@ -220,18 +246,19 @@ for t in top_chunks_after_rerank:
print("== " + t)
```
-```txt title="Output"
-Here are the top 3 chunks after rerank:
-== Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first
-== stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,
-== series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by
-```
+ Here are the top 3 chunks after rerank:
+ == Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first
+ == stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,
+ == series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by
+
## Step 3 - Generate the model final answer, given the retrieved and reranked chunks
-```python PYTHON
+
+```python
+# preamble containing instructions about the task and the desired style for the output.
preamble = """
-## Task & Context
+## Task & Context
You help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.
## Style Guide
@@ -239,13 +266,16 @@ Unless the user asks for a different style of answer, you should answer in full
"""
```
-```python PYTHON
+
+```python
+# retrieved documents
documents = [
{"title": "chunk 0", "snippet": top_chunks_after_rerank[0]},
{"title": "chunk 1", "snippet": top_chunks_after_rerank[1]},
{"title": "chunk 2", "snippet": top_chunks_after_rerank[2]},
]
+# get model response
response = co.chat(
message=query,
documents=documents,
@@ -258,23 +288,22 @@ print("Final answer:")
print(response.text)
```
-```txt title="Output"
-Final answer:
-Here are the key crew members involved in 'Dune: Part Two':
-
-- Denis Villeneuve: director and producer
-- Jon Spaihts: co-writer of the screenplay
-- Mary Parent and Cale Boyter: producers
-- Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Richard P. Rubinstein, John Harrison, Herbert W. Gain and Kevin J. Anderson: executive producers
-- Joe Walker: editor
-- Brad Riker: supervising art director
-- Patrice Vermette: production designer
-- Paul Lambert: visual effects supervisor
-- Gerd Nefzer: special effects supervisor
-- Thomas Struthers: stunt coordinator.
-
-A number of crew members from the first film returned for the sequel, which is set to be released in 2024.
-```
+ Final answer:
+ Here are the key crew members involved in 'Dune: Part Two':
+
+ - Denis Villeneuve: director and producer
+ - Jon Spaihts: co-writer of the screenplay
+ - Mary Parent and Cale Boyter: producers
+ - Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Richard P. Rubinstein, John Harrison, Herbert W. Gain and Kevin J. Anderson: executive producers
+ - Joe Walker: editor
+ - Brad Riker: supervising art director
+ - Patrice Vermette: production designer
+ - Paul Lambert: visual effects supervisor
+ - Gerd Nefzer: special effects supervisor
+ - Thomas Struthers: stunt coordinator.
+
+ A number of crew members from the first film returned for the sequel, which is set to be released in 2024.
+
Note: this is indeed the answer you'd expect, and here was the passage of text in wikipedia explaining it!
@@ -283,52 +312,54 @@ Note: this is indeed the answer you'd expect, and here was the passage of text i
## Bonus: Citations come for free with Cohere! 🎉
At Cohere, all RAG calls come with... precise citations! 🎉
-The model cites which groups of words, in the RAG chunks, were used to generate the final answer.
-These citations make it easy to check where the model’s generated response claims are coming from.
-They help users gain visibility into the model reasoning, and sanity check the final model generation.
+The model cites which groups of words, in the RAG chunks, were used to generate the final answer.
+These citations make it easy to check where the model’s generated response claims are coming from.
+They help users gain visibility into the model reasoning, and sanity check the final model generation.
These citations are optional — you can decide to ignore them.
-```python PYTHON
+
+
+```python
print("Citations that support the final answer:")
for cite in response.citations:
print(cite)
```
-```txt title="Output"
-Citations that support the final answer:
-{'start': 63, 'end': 79, 'text': 'Denis Villeneuve', 'document_ids': ['doc_0']}
-{'start': 81, 'end': 102, 'text': 'director and producer', 'document_ids': ['doc_0']}
-{'start': 105, 'end': 116, 'text': 'Jon Spaihts', 'document_ids': ['doc_0']}
-{'start': 118, 'end': 145, 'text': 'co-writer of the screenplay', 'document_ids': ['doc_0']}
-{'start': 148, 'end': 159, 'text': 'Mary Parent', 'document_ids': ['doc_1']}
-{'start': 164, 'end': 175, 'text': 'Cale Boyter', 'document_ids': ['doc_1']}
-{'start': 177, 'end': 186, 'text': 'producers', 'document_ids': ['doc_1']}
-{'start': 190, 'end': 204, 'text': 'Tanya Lapointe', 'document_ids': ['doc_1']}
-{'start': 206, 'end': 219, 'text': 'Brian Herbert', 'document_ids': ['doc_1']}
-{'start': 221, 'end': 234, 'text': 'Byron Merritt', 'document_ids': ['doc_1']}
-{'start': 236, 'end': 247, 'text': 'Kim Herbert', 'document_ids': ['doc_1']}
-{'start': 249, 'end': 260, 'text': 'Thomas Tull', 'document_ids': ['doc_1']}
-{'start': 262, 'end': 283, 'text': 'Richard P. Rubinstein', 'document_ids': ['doc_1']}
-{'start': 285, 'end': 298, 'text': 'John Harrison', 'document_ids': ['doc_1']}
-{'start': 300, 'end': 315, 'text': 'Herbert W. Gain', 'document_ids': ['doc_1']}
-{'start': 320, 'end': 337, 'text': 'Kevin J. Anderson', 'document_ids': ['doc_1']}
-{'start': 339, 'end': 358, 'text': 'executive producers', 'document_ids': ['doc_1']}
-{'start': 362, 'end': 372, 'text': 'Joe Walker', 'document_ids': ['doc_2']}
-{'start': 374, 'end': 380, 'text': 'editor', 'document_ids': ['doc_2']}
-{'start': 383, 'end': 393, 'text': 'Brad Riker', 'document_ids': ['doc_2']}
-{'start': 395, 'end': 419, 'text': 'supervising art director', 'document_ids': ['doc_2']}
-{'start': 422, 'end': 438, 'text': 'Patrice Vermette', 'document_ids': ['doc_2']}
-{'start': 440, 'end': 459, 'text': 'production designer', 'document_ids': ['doc_2']}
-{'start': 462, 'end': 474, 'text': 'Paul Lambert', 'document_ids': ['doc_2']}
-{'start': 476, 'end': 501, 'text': 'visual effects supervisor', 'document_ids': ['doc_2']}
-{'start': 504, 'end': 515, 'text': 'Gerd Nefzer', 'document_ids': ['doc_2']}
-{'start': 517, 'end': 543, 'text': 'special effects supervisor', 'document_ids': ['doc_2']}
-{'start': 546, 'end': 562, 'text': 'Thomas Struthers', 'document_ids': ['doc_2']}
-{'start': 564, 'end': 582, 'text': 'stunt coordinator.', 'document_ids': ['doc_2']}
-{'start': 686, 'end': 691, 'text': '2024.', 'document_ids': ['doc_0']}
-```
-
-```python PYTHON
+ Citations that support the final answer:
+ {'start': 63, 'end': 79, 'text': 'Denis Villeneuve', 'document_ids': ['doc_0']}
+ {'start': 81, 'end': 102, 'text': 'director and producer', 'document_ids': ['doc_0']}
+ {'start': 105, 'end': 116, 'text': 'Jon Spaihts', 'document_ids': ['doc_0']}
+ {'start': 118, 'end': 145, 'text': 'co-writer of the screenplay', 'document_ids': ['doc_0']}
+ {'start': 148, 'end': 159, 'text': 'Mary Parent', 'document_ids': ['doc_1']}
+ {'start': 164, 'end': 175, 'text': 'Cale Boyter', 'document_ids': ['doc_1']}
+ {'start': 177, 'end': 186, 'text': 'producers', 'document_ids': ['doc_1']}
+ {'start': 190, 'end': 204, 'text': 'Tanya Lapointe', 'document_ids': ['doc_1']}
+ {'start': 206, 'end': 219, 'text': 'Brian Herbert', 'document_ids': ['doc_1']}
+ {'start': 221, 'end': 234, 'text': 'Byron Merritt', 'document_ids': ['doc_1']}
+ {'start': 236, 'end': 247, 'text': 'Kim Herbert', 'document_ids': ['doc_1']}
+ {'start': 249, 'end': 260, 'text': 'Thomas Tull', 'document_ids': ['doc_1']}
+ {'start': 262, 'end': 283, 'text': 'Richard P. Rubinstein', 'document_ids': ['doc_1']}
+ {'start': 285, 'end': 298, 'text': 'John Harrison', 'document_ids': ['doc_1']}
+ {'start': 300, 'end': 315, 'text': 'Herbert W. Gain', 'document_ids': ['doc_1']}
+ {'start': 320, 'end': 337, 'text': 'Kevin J. Anderson', 'document_ids': ['doc_1']}
+ {'start': 339, 'end': 358, 'text': 'executive producers', 'document_ids': ['doc_1']}
+ {'start': 362, 'end': 372, 'text': 'Joe Walker', 'document_ids': ['doc_2']}
+ {'start': 374, 'end': 380, 'text': 'editor', 'document_ids': ['doc_2']}
+ {'start': 383, 'end': 393, 'text': 'Brad Riker', 'document_ids': ['doc_2']}
+ {'start': 395, 'end': 419, 'text': 'supervising art director', 'document_ids': ['doc_2']}
+ {'start': 422, 'end': 438, 'text': 'Patrice Vermette', 'document_ids': ['doc_2']}
+ {'start': 440, 'end': 459, 'text': 'production designer', 'document_ids': ['doc_2']}
+ {'start': 462, 'end': 474, 'text': 'Paul Lambert', 'document_ids': ['doc_2']}
+ {'start': 476, 'end': 501, 'text': 'visual effects supervisor', 'document_ids': ['doc_2']}
+ {'start': 504, 'end': 515, 'text': 'Gerd Nefzer', 'document_ids': ['doc_2']}
+ {'start': 517, 'end': 543, 'text': 'special effects supervisor', 'document_ids': ['doc_2']}
+ {'start': 546, 'end': 562, 'text': 'Thomas Struthers', 'document_ids': ['doc_2']}
+ {'start': 564, 'end': 582, 'text': 'stunt coordinator.', 'document_ids': ['doc_2']}
+ {'start': 686, 'end': 691, 'text': '2024.', 'document_ids': ['doc_0']}
+
+
+
+```python
def insert_citations_in_order(text, citations):
"""
A helper function to pretty print citations.
@@ -369,23 +400,27 @@ print(insert_citations_in_order(response.text, response.citations))
```
-```markdown title="Output"
-Here are the key crew members involved in 'Dune: Part Two':
-
-- **Denis Villeneuve**[1]: **director and producer**[1]
-- **Jon Spaihts**[1]: **co-writer of the screenplay**[1]
-- **Mary Parent**[2] and **Cale Boyter**[2]: **producers**[2]
-- **Tanya Lapointe**[2], **Brian Herbert**[2], **Byron Merritt**[2], **Kim Herbert**[2], **Thomas Tull**[2], **Richard P. Rubinstein**[2], **John Harrison**[2], **Herbert W. Gain**[2] and **Kevin J. Anderson**[2]: **executive producers**[2]
-- **Joe Walker**[3]: **editor**[3]
-- **Brad Riker**[3]: **supervising art director**[3]
-- **Patrice Vermette**[3]: **production designer**[3]
-- **Paul Lambert**[3]: **visual effects supervisor**[3]
-- **Gerd Nefzer**[3]: **special effects supervisor**[3]
-- **Thomas Struthers**[3]: **stunt coordinator.**[3]
-
-A number of crew members from the first film returned for the sequel, which is set to be released in **2024.**[1]
-
-[1] source: "Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first"
-[2] source: "stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,"
-[3] source: "series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by"
+ Here are the key crew members involved in 'Dune: Part Two':
+
+ - **Denis Villeneuve**[1]: **director and producer**[1]
+ - **Jon Spaihts**[1]: **co-writer of the screenplay**[1]
+ - **Mary Parent**[2] and **Cale Boyter**[2]: **producers**[2]
+ - **Tanya Lapointe**[2], **Brian Herbert**[2], **Byron Merritt**[2], **Kim Herbert**[2], **Thomas Tull**[2], **Richard P. Rubinstein**[2], **John Harrison**[2], **Herbert W. Gain**[2] and **Kevin J. Anderson**[2]: **executive producers**[2]
+ - **Joe Walker**[3]: **editor**[3]
+ - **Brad Riker**[3]: **supervising art director**[3]
+ - **Patrice Vermette**[3]: **production designer**[3]
+ - **Paul Lambert**[3]: **visual effects supervisor**[3]
+ - **Gerd Nefzer**[3]: **special effects supervisor**[3]
+ - **Thomas Struthers**[3]: **stunt coordinator.**[3]
+
+ A number of crew members from the first film returned for the sequel, which is set to be released in **2024.**[1]
+
+ [1] source: "Dune: Part Two is a 2024 American epic science fiction film directed and produced by Denis Villeneuve, who co-wrote the screenplay with Jon Spaihts. The sequel to Dune (2021) adapts the 1965 novel Dune by Frank Herbert and follows Paul Atreides as he unites with the Fremen people of the desert planet Arrakis to wage war against House Harkonnen. Timothée Chalamet, Rebecca Ferguson, Josh Brolin, Stellan Skarsgård, Dave Bautista, Zendaya, Charlotte Rampling, and Javier Bardem reprise their roles from the first"
+ [2] source: "stunt coordinator. Dune: Part Two was produced by Villeneuve, Mary Parent, and Cale Boyter, with Tanya Lapointe, Brian Herbert, Byron Merritt, Kim Herbert, Thomas Tull, Jon Spaihts, Richard P. Rubinstein, John Harrison, and Herbert W. Gain serving as executive producers and Kevin J. Anderson as creative consultant. Legendary CEO Joshua Grode confirmed in April 2019 that they plan to make a sequel, adding that "there's a logical place to stop the [first] movie before the book is over".In December 2020,"
+ [3] source: "series. Villeneuve ultimately secured a two-film deal with Warner Bros. Pictures, in the same style as the two-part adaption of Stephen King's It in 2017 and 2019. In January 2019, Joe Walker was confirmed to be serving as the film's editor. Other crew included Brad Riker as supervising art director, Patrice Vermette as production designer, Paul Lambert as visual effects supervisor, Gerd Nefzer as special effects supervisor, and Thomas Struthers as stunt coordinator. Dune: Part Two was produced by"
+
+
+
+```python
+
```
diff --git a/fern/pages/cookbooks/basic-semantic-search.mdx b/fern/pages/cookbooks/basic-semantic-search.mdx
index 32c8f7af0..dba9afc2b 100644
--- a/fern/pages/cookbooks/basic-semantic-search.mdx
+++ b/fern/pages/cookbooks/basic-semantic-search.mdx
@@ -1,42 +1,50 @@
---
-title: Basic Semantic Search with Cohere Models
+title: Basic Semantic Search
slug: /page/basic-semantic-search
description: "This page describes how to do basic semantic search with Cohere's models."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, semantic search"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-Language models give computers the ability to search by meaning and go beyond searching by matching keywords. This capability is called semantic search.
-
+
+
+Language models give computers the ability to search by meaning and go beyond searching by matching keywords. This capability is called semantic search.
+
+
In this notebook, we'll build a simple semantic search engine. The applications of semantic search go beyond building a web search engine. They can empower a private search engine for internal documents or records. It can also be used to power features like StackOverflow's "similar questions" feature.
1. Get the archive of questions
2. [Embed](https://docs.cohere.ai/embed-reference/) the archive
3. Search using an index and nearest neighbor search
-4. Visualize the archive based on the embeddings
+4. Visualize the archive based on the embeddings
+
+
+```python
+# Install Cohere for embeddings, Umap to reduce embeddings to 2 dimensions,
+# Altair for visualization, Annoy for approximate nearest neighbor search
+# TODO: upgrade to "cohere>5"!pip install "cohere<5" umap-learn altair annoy datasets tqdm
+```
And if you're running an older version of the SDK, you might need to upgrade it like so:
-```python PYTHON
+
+```python
#!pip install --upgrade cohere
```
-Get your Cohere API key by [signing up here](https://dashboard.cohere.com/register). Paste it in the cell below.
+Get your Cohere API key by [signing up here](https://os.cohere.ai/register). Paste it in the cell below.
+
+## 1. Getting Set up
-## 1. Getting Set Up
-```python PYTHON
+```python
#@title Import libraries (Run this cell to execute required code) {display-mode: "form"}
import cohere
@@ -54,144 +62,169 @@ warnings.filterwarnings('ignore')
pd.set_option('display.max_colwidth', None)
```
-You'll need your API key for this next cell. [Sign up to Cohere](https://dashboard.cohere.com/) and get one if you haven't yet.
+You'll need your API key for this next cell. [Sign up to Cohere](https://os.cohere.ai/) and get one if you haven't yet.
-```python PYTHON
+
+```python
+# We'll set up the name of the model we want to use, the API key, and the input type.
+# Create and retrieve a Cohere API key from dashboard.cohere.ai/welcome/register
+# Paste your API key here. Remember to not share publicly
model_name = "embed-english-v3.0"
api_key = ""
input_type_embed = "search_document"
+# Now we'll set up the cohere client.
co = cohere.Client(api_key)
```
## 2. Get The Archive of Questions
-
We'll use the [trec](https://www.tensorflow.org/datasets/catalog/trec) dataset which is made up of questions and their categories.
-```python PYTHON
+
+```python
+# Get dataset
dataset = load_dataset("trec", split="train")
+# Import into a pandas dataframe, take only the first 1000 rows
df = pd.DataFrame(dataset)[:1000]
+# Preview the data to ensure it has loaded correctly
df.head(10)
```
+
+
+
-
-
-
- |
- label-coarse |
- label-fine |
- text |
-
-
-
-
- 0 |
- 0 |
- 0 |
- How did serfdom develop in and then leave Russia ? |
-
-
- 1 |
- 1 |
- 1 |
- What films featured the character Popeye Doyle ? |
-
-
- 2 |
- 0 |
- 0 |
- How can I find a list of celebrities ' real names ? |
-
-
- 3 |
- 1 |
- 2 |
-
- What fowl grabs the spotlight after the Chinese Year of the Monkey ?
- |
-
-
- 4 |
- 2 |
- 3 |
- What is the full form of .com ? |
-
-
- 5 |
- 3 |
- 4 |
- What contemptible scoundrel stole the cork from my lunch ? |
-
-
- 6 |
- 3 |
- 5 |
- What team did baseball 's St. Louis Browns become ? |
-
-
- 7 |
- 3 |
- 6 |
- What is the oldest profession ? |
-
-
- 8 |
- 0 |
- 7 |
- What are liver enzymes ? |
-
-
- 9 |
- 3 |
- 4 |
- Name the scar-faced bounty hunter of The Old West . |
-
-
-
+
+
+
+
+ |
+ label-coarse |
+ label-fine |
+ text |
+
+
+
+
+ 0 |
+ 0 |
+ 0 |
+ How did serfdom develop in and then leave Russia ? |
+
+
+ 1 |
+ 1 |
+ 1 |
+ What films featured the character Popeye Doyle ? |
+
+
+ 2 |
+ 0 |
+ 0 |
+ How can I find a list of celebrities ' real names ? |
+
+
+ 3 |
+ 1 |
+ 2 |
+ What fowl grabs the spotlight after the Chinese Year of the Monkey ? |
+
+
+ 4 |
+ 2 |
+ 3 |
+ What is the full form of .com ? |
+
+
+ 5 |
+ 3 |
+ 4 |
+ What contemptible scoundrel stole the cork from my lunch ? |
+
+
+ 6 |
+ 3 |
+ 5 |
+ What team did baseball 's St. Louis Browns become ? |
+
+
+ 7 |
+ 3 |
+ 6 |
+ What is the oldest profession ? |
+
+
+ 8 |
+ 0 |
+ 7 |
+ What are liver enzymes ? |
+
+
+ 9 |
+ 3 |
+ 4 |
+ Name the scar-faced bounty hunter of The Old West . |
+
+
+
-## 2. Embed the archive
+
+## 2. Embed the archive
The next step is to embed the text of the questions.
-
+
To get a thousand embeddings of this length should take about fifteen seconds.
-```python PYTHON
+
+```python
+# Get the embeddings
embeds = co.embed(texts=list(df['text']),
model=model_name,
input_type=input_type_embed).embeddings
```
-```python PYTHON
+
+```python
+# Check the dimensions of the embeddings
embeds = np.array(embeds)
embeds.shape
```
-```
-(1000, 4096)
-```
-## 3. Search using an index and nearest neighbor search
-
+ (1000, 4096)
+
+
+
+## 3. Search using an index and nearest neighbor search
+
Let's now use [Annoy](https://github.com/spotify/annoy) to build an index that stores the embeddings in a way that is optimized for fast search. This approach scales well to a large number of texts (other options include [Faiss](https://github.com/facebookresearch/faiss), [ScaNN](https://github.com/google-research/google-research/tree/master/scann), and [PyNNDescent](https://github.com/lmcinnes/pynndescent)).
After building the index, we can use it to retrieve the nearest neighbors either of existing questions (section 3.1), or of new questions that we embed (section 3.2).
-```python PYTHON
+
+```python
+# Create the search index, pass the size of embedding
search_index = AnnoyIndex(embeds.shape[1], 'angular')
+# Add all the vectors to the search index
for i in range(len(embeds)):
search_index.add_item(i, embeds[i])
@@ -199,105 +232,131 @@ search_index.build(10) # 10 trees
search_index.save('test.ann')
```
-```
-True
-```
-### 3.1. Find the neighbors of an example from the dataset
+
+ True
+
+
+
+### 3.1. Find the neighbors of an example from the dataset
If we're only interested in measuring the distance between the questions in the dataset (no outside queries), a simple way is to calculate the distance between every pair of embeddings we have.
-```python PYTHON
+
+```python
+# Choose an example (we'll retrieve others similar to it)
example_id = 92
+# Retrieve nearest neighbors
similar_item_ids = search_index.get_nns_by_item(example_id,10,
include_distances=True)
-results = pd.DataFrame(data={'texts': df.iloc[similar_item_ids[0]]['text'],
+# Format and print the text and distances
+results = pd.DataFrame(data={'texts': df.iloc[similar_item_ids[0]]['text'],
'distance': similar_item_ids[1]}).drop(example_id)
print(f"Question:'{df.iloc[example_id]['text']}'\nNearest neighbors:")
results
```
-```
-Question:'What are bear and bull markets ?'
-Nearest neighbors:
-```
+ Question:'What are bear and bull markets ?'
+ Nearest neighbors:
+
+
+
+
-
-
-
- |
- texts |
- distance |
-
-
-
-
- 614 |
- What animals do you find in the stock market ? |
- 0.904278 |
-
-
- 137 |
- What are equity securities ? |
- 0.992819 |
-
-
- 513 |
- What do economists do ? |
- 1.066583 |
-
-
- 307 |
- What does NASDAQ stand for ? |
- 1.080738 |
-
-
- 363 |
- What does it mean `` Rupee Depreciates '' ? |
- 1.086724 |
-
-
- 932 |
- Why did the world enter a global depression in 1929 ? |
- 1.099370 |
-
-
- 547 |
- Where can stocks be traded on-line ? |
- 1.105368 |
-
-
- 922 |
- What is the difference between a median and a mean ? |
- 1.141870 |
-
-
- 601 |
- What is `` the bear of beers '' ? |
- 1.154140 |
-
-
-
+
+
+
+
+ |
+ texts |
+ distance |
+
+
+
+
+ 614 |
+ What animals do you find in the stock market ? |
+ 0.904278 |
+
+
+ 137 |
+ What are equity securities ? |
+ 0.992819 |
+
+
+ 513 |
+ What do economists do ? |
+ 1.066583 |
+
+
+ 307 |
+ What does NASDAQ stand for ? |
+ 1.080738 |
+
+
+ 363 |
+ What does it mean `` Rupee Depreciates '' ? |
+ 1.086724 |
+
+
+ 932 |
+ Why did the world enter a global depression in 1929 ? |
+ 1.099370 |
+
+
+ 547 |
+ Where can stocks be traded on-line ? |
+ 1.105368 |
+
+
+ 922 |
+ What is the difference between a median and a mean ? |
+ 1.141870 |
+
+
+ 601 |
+ What is `` the bear of beers '' ? |
+ 1.154140 |
+
+
+
-### 3.2. Find the neighbors of a user query
+
+### 3.2. Find the neighbors of a user query
We're not limited to searching using existing items. If we get a query, we can embed it and find its nearest neighbors from the dataset.
-```python PYTHON
+
+```python
query = "What is the tallest mountain in the world?"
input_type_query = "search_query"
+# Get the query's embedding
query_embed = co.embed(texts=[query],
model=model_name,
input_type=input_type_query).embeddings
+# Retrieve the nearest neighbors
similar_item_ids = search_index.get_nns_by_vector(query_embed[0],10,
include_distances=True)
-query_results = pd.DataFrame(data={'texts': df.iloc[similar_item_ids[0]]['text'],
+# Format the results
+query_results = pd.DataFrame(data={'texts': df.iloc[similar_item_ids[0]]['text'],
'distance': similar_item_ids[1]})
@@ -305,94 +364,109 @@ print(f"Query:'{query}'\nNearest neighbors:")
print(query_results) # NOTE: Your results might look slightly different to ours.
```
-```
-Query:'What is the tallest mountain in the world?'
-Nearest neighbors:
-```
+ Query:'What is the tallest mountain in the world?'
+ Nearest neighbors:
+
+
+
+
-
-
-
- |
- texts |
- distance |
-
-
-
-
- 236 |
- What is the name of the tallest mountain in the world ? |
- 0.447309 |
-
-
- 670 |
- What is the highest mountain in the world ? |
- 0.552254 |
-
-
- 412 |
-
- What was the highest mountain on earth before Mount Everest was
- discovered ?
- |
- 0.801252 |
-
-
- 907 |
-
- What mountain range is traversed by the highest railroad in the world
- ?
- |
- 0.929516 |
-
-
- 435 |
- What is the highest peak in Africa ? |
- 0.930806 |
-
-
- 109 |
- Where is the highest point in Japan ? |
- 0.977315 |
-
-
- 901 |
- What 's the longest river in the world ? |
- 1.064209 |
-
-
- 114 |
- What is the largest snake in the world ? |
- 1.076390 |
-
-
- 962 |
- What 's the second-largest island in the world ? |
- 1.088034 |
-
-
- 27 |
- What is the highest waterfall in the United States ? |
- 1.091145 |
-
-
-
+
+
+
+
+ |
+ texts |
+ distance |
+
+
+
+
+ 236 |
+ What is the name of the tallest mountain in the world ? |
+ 0.447309 |
+
+
+ 670 |
+ What is the highest mountain in the world ? |
+ 0.552254 |
+
+
+ 412 |
+ What was the highest mountain on earth before Mount Everest was discovered ? |
+ 0.801252 |
+
+
+ 907 |
+ What mountain range is traversed by the highest railroad in the world ? |
+ 0.929516 |
+
+
+ 435 |
+ What is the highest peak in Africa ? |
+ 0.930806 |
+
+
+ 109 |
+ Where is the highest point in Japan ? |
+ 0.977315 |
+
+
+ 901 |
+ What 's the longest river in the world ? |
+ 1.064209 |
+
+
+ 114 |
+ What is the largest snake in the world ? |
+ 1.076390 |
+
+
+ 962 |
+ What 's the second-largest island in the world ? |
+ 1.088034 |
+
+
+ 27 |
+ What is the highest waterfall in the United States ? |
+ 1.091145 |
+
+
+
-## 4. Visualizing the archive
+
+## 4. Visualizing the archive
Finally, let's plot out all the questions onto a 2D chart so you're able to visualize the semantic similarities of this dataset!
-```python PYTHON
+
+```python
#@title Plot the archive {display-mode: "form"}
-reducer = umap.UMAP(n_neighbors=20)
+# UMAP reduces the dimensions from 1024 to 2 dimensions that we can plot
+reducer = umap.UMAP(n_neighbors=20)
umap_embeds = reducer.fit_transform(embeds)
+# Prepare the data to plot and interactive visualization
+# using Altair
df_explore = pd.DataFrame(data={'text': df['text']})
df_explore['x'] = umap_embeds[:,0]
df_explore['y'] = umap_embeds[:,1]
+# Plot
chart = alt.Chart(df_explore).mark_circle(size=60).encode(
x=#'x',
alt.X('x',
@@ -410,10 +484,21 @@ chart = alt.Chart(df_explore).mark_circle(size=60).encode(
chart.interactive()
```
+
+
+
+
+
+
+
Hover over the points to read the text. Do you see some of the patterns in clustered points? Similar questions, or questions asking about similar topics?
-This concludes this introductory guide to semantic search using sentence embeddings. As you continue the path of building a search product additional considerations arise (like dealing with long texts, or finetuning to better improve the embeddings for a specific use case).
+This concludes this introductory guide to semantic search using sentence embeddings. As you continue the path of building a search product additional considerations arise (like dealing with long texts, or finetuning to better improve the embeddings for a specific use case).
+
We can’t wait to see what you start building! Share your projects or find support on [Discord](https://discord.com/invite/co-mmunity).
+
+
+
diff --git a/fern/pages/cookbooks/basic-tool-use.mdx b/fern/pages/cookbooks/basic-tool-use.mdx
index 6a92f89e5..d5559db4c 100644
--- a/fern/pages/cookbooks/basic-tool-use.mdx
+++ b/fern/pages/cookbooks/basic-tool-use.mdx
@@ -1,39 +1,60 @@
---
-title: Getting Started with Basic Tool Use
+title: Basic Tool Use
slug: /page/basic-tool-use
description: "This page describes how to work with Cohere's basic tool use functionality."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, tool use, AI agents"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-Tool use allows customers to **connect their large language models to external tools, such as search engines, APIs, functions, and databases**.
-This allows the customer to unlock a richer set of model behaviors by, for instance, leveraging data stored in tools, taking actions through APIs, interacting with a vector database, or querying a search engine.
+
-Below, we illustrate tool use in four steps:
+
+
+
+
+Tool use allows customers to **connect their large language models to external tools like search engines, APIs, functions, databases**, etc.
+
+This allows the customer's model to unlock a richer set of behaviors by leveraging data stored in tools, taking actions through APIs, interacting with a vector database, querying a search engine, etc.
+
+This is particularly valuable for enterprise customers, since a lot of enterprise data lives in external sources.
+
+Tool Use consists of 4 steps:
- Step 1: the user configures the request to the model
-- Step 2: the model uses context to **determine which tool(s) to use and how**
-- Step 3: the tool calls are executed
-- Step 4: the model **generates a final answer with precise citations** based on the tool results
+- Step 2: the **model smartly decides which tool(s) to use and how**
+- Step 3: the tool calls are executed to mock database
+- Step 4: the **model generates a final answer with precise citations based on the tool results**
+
+
+```python
+# we'll use Cohere to do Tool Use
+# TODO: upgrade to "cohere>5"
+%pip install "cohere<5" --quiet
+```
+
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m52.8/52.8 kB[0m [31m1.6 MB/s[0m eta [36m0:00:00[0m
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m28.1 MB/s[0m eta [36m0:00:00[0m
+ [?25h
-```python PYTHON
+
+```python
import cohere, json
API_KEY = "..." # fill in your Cohere API key here
co = cohere.Client(API_KEY)
```
## Step 0: Create a mock database
+First, we'll define the mock data that our tools will query. This data represents sales reports and a product catalog.
-Before we can illustrate tool use, we first need to do some setup. Here, we'll define the mock data that our tools will query. This data represents sales reports and a product catalog.
-```python PYTHON
+```python
+# Mock database containing daily sales reports
sales_database = {
'2023-09-28': {
'total_sales_amount': 5000,
@@ -49,6 +70,7 @@ sales_database = {
}
}
+# Mock product catalog
product_catalog = {
'Electronics': [
{'product_id': 'E1001', 'name': 'Smartphone', 'price': 500, 'stock_level': 20},
@@ -64,9 +86,12 @@ product_catalog = {
```
Now, we'll define the tools that simulate querying this database.
-For example, you could use the API of an enterprise sales platform.
+You could for example use the API of an enterprise sales platform.
+
+
+
-```python PYTHON
+```python
def query_daily_sales_report(day: str) -> dict:
"""
Function to retrieve the sales report for the given day
@@ -98,20 +123,24 @@ functions_map = {
}
```
-## Step 1 - User configures the request to the model
+## Step 1 - the user configures the request to the model
The developer provides a few things to the model:
-
- A preamble containing instructions about the task and the desired style for the output.
- The user request.
- A list of tools to the model.
- (Optionally) a chat history for the model to work with.
+
You can specify one or many tools to the model. Every tool needs to be described with a JSON schema, indicating the tool name, description, and parameters (code snippets below).
In our example, we provide two tools to the model: `daily_sales_report` and `product_catalog`.
-```python PYTHON
+
+
+```python
+# tool descriptions that the model has access to
+# note: Cohere always adds a "directly_answer" tool under the hood, so that the model can decide to not leverage any tool, if they're not needed.
tools = [
{
"name": "query_daily_sales_report",
@@ -138,29 +167,32 @@ tools = [
]
```
-Now let's define the user request.
+Now let's define the user request.
In our example we'll use: "Can you provide a sales summary for 29th September 2023, and also give me the details of all products in the 'Electronics' category that were sold that day, including their prices and stock levels?"
Only a langage model with Tool Use can answer this request: it requires looking up information in the right external tools (step 2), and then providing a final answer based on the tool results (step 4).
-```python PYTHON
+
+```python
+# preamble containing instructions about the task and the desired style for the output.
preamble = """
-## Task & Context
+## Task & Context
You help people answer their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You should focus on serving the user's needs as best you can, which will be wide-ranging.
## Style Guide
Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.
"""
+# user request
message = "Can you provide a sales summary for 29th September 2023, and also give me some details about the products in the 'Electronics' category, for example their prices and stock levels?"
```
-## Step 2 – The model smartly decides which tool(s) to use and how
-
+## Step 2 – the model smartly decides which tool(s) to use and how
The model intelligently selects the right tool(s) to call -- and the right parameters for each tool call -- based on the content of the user message.
-```python PYTHON
+
+```python
response = co.chat(
message=message,
tools=tools,
@@ -168,32 +200,38 @@ response = co.chat(
model="command-r"
)
+# Note that the Cohere Chat API also exposes:
+# - stream (for streaming mode)
+# - chat_history
+# - among other parameters
+# See https://docs.cohere.com/reference/chat for details.
print("The model recommends doing the following tool calls:")
print("\n".join(str(tool_call) for tool_call in response.tool_calls))
```
-```
-The model recommends doing the following tool calls:
-cohere.ToolCall {
- name: query_daily_sales_report
- parameters: {'day': '2023-09-29'}
- generation_id: eaf955e3-623d-4796-bf51-23b07c66ed2c
-}
-cohere.ToolCall {
- name: query_product_catalog
- parameters: {'category': 'Electronics'}
- generation_id: eaf955e3-623d-4796-bf51-23b07c66ed2c
-}
-```
+ The model recommends doing the following tool calls:
+ cohere.ToolCall {
+ name: query_daily_sales_report
+ parameters: {'day': '2023-09-29'}
+ generation_id: eaf955e3-623d-4796-bf51-23b07c66ed2c
+ }
+ cohere.ToolCall {
+ name: query_product_catalog
+ parameters: {'category': 'Electronics'}
+ generation_id: eaf955e3-623d-4796-bf51-23b07c66ed2c
+ }
+
-## Step 3 – The tool calls are executed
+## Step 3 – the tool calls are executed
-You can now execute the appropriate calls, using the tool calls and tool parameters generated by the model.
+You can then execute the appropriate calls, using the tool calls and tool parameters generated by the model.
These tool calls return tool results that will be fed to the model in Step 4.
-```python PYTHON
+
+```python
tool_results = []
+# Iterate over the tool calls generated by the model
for tool_call in response.tool_calls:
# here is where you would call the tool recommended by the model, using the parameters recommended by the model
print(f"= running tool {tool_call.name}, with parameters: {tool_call.parameters}")
@@ -211,70 +249,77 @@ print("Tool results that will be fed back to the model in step 4:")
print(json.dumps(tool_results, indent=4))
```
-```
-= running tool query_daily_sales_report, with parameters: {'day': '2023-09-29'}
-== tool results: [{'date': '2023-09-29', 'summary': 'Total Sales Amount: 10000, Total Units Sold: 250'}]
-= running tool query_product_catalog, with parameters: {'category': 'Electronics'}
-== tool results: [{'category': 'Electronics', 'products': [{'product_id': 'E1001', 'name': 'Smartphone', 'price': 500, 'stock_level': 20}, {'product_id': 'E1002', 'name': 'Laptop', 'price': 1000, 'stock_level': 15}, {'product_id': 'E1003', 'name': 'Tablet', 'price': 300, 'stock_level': 25}]}]
-Tool results that will be fed back to the model in step 4:
-[
- {
- "call": {
- "name": "query_daily_sales_report",
- "parameters": {
- "day": "2023-09-29"
+ = running tool query_daily_sales_report, with parameters: {'day': '2023-09-29'}
+ == tool results: [{'date': '2023-09-29', 'summary': 'Total Sales Amount: 10000, Total Units Sold: 250'}]
+ = running tool query_product_catalog, with parameters: {'category': 'Electronics'}
+ == tool results: [{'category': 'Electronics', 'products': [{'product_id': 'E1001', 'name': 'Smartphone', 'price': 500, 'stock_level': 20}, {'product_id': 'E1002', 'name': 'Laptop', 'price': 1000, 'stock_level': 15}, {'product_id': 'E1003', 'name': 'Tablet', 'price': 300, 'stock_level': 25}]}]
+ Tool results that will be fed back to the model in step 4:
+ [
+ {
+ "call": {
+ "name": "query_daily_sales_report",
+ "parameters": {
+ "day": "2023-09-29"
+ },
+ "generation_id": "eaf955e3-623d-4796-bf51-23b07c66ed2c"
},
- "generation_id": "eaf955e3-623d-4796-bf51-23b07c66ed2c"
+ "outputs": [
+ {
+ "date": "2023-09-29",
+ "summary": "Total Sales Amount: 10000, Total Units Sold: 250"
+ }
+ ]
},
- "outputs": [
- {
- "date": "2023-09-29",
- "summary": "Total Sales Amount: 10000, Total Units Sold: 250"
- }
- ]
- },
- {
- "call": {
- "name": "query_product_catalog",
- "parameters": {
- "category": "Electronics"
+ {
+ "call": {
+ "name": "query_product_catalog",
+ "parameters": {
+ "category": "Electronics"
+ },
+ "generation_id": "eaf955e3-623d-4796-bf51-23b07c66ed2c"
},
- "generation_id": "eaf955e3-623d-4796-bf51-23b07c66ed2c"
- },
- "outputs": [
- {
- "category": "Electronics",
- "products": [
- {
- "product_id": "E1001",
- "name": "Smartphone",
- "price": 500,
- "stock_level": 20
- },
- {
- "product_id": "E1002",
- "name": "Laptop",
- "price": 1000,
- "stock_level": 15
- },
- {
- "product_id": "E1003",
- "name": "Tablet",
- "price": 300,
- "stock_level": 25
- }
- ]
- }
- ]
- }
-]
-```
+ "outputs": [
+ {
+ "category": "Electronics",
+ "products": [
+ {
+ "product_id": "E1001",
+ "name": "Smartphone",
+ "price": 500,
+ "stock_level": 20
+ },
+ {
+ "product_id": "E1002",
+ "name": "Laptop",
+ "price": 1000,
+ "stock_level": 15
+ },
+ {
+ "product_id": "E1003",
+ "name": "Tablet",
+ "price": 300,
+ "stock_level": 25
+ }
+ ]
+ }
+ ]
+ }
+ ]
+
+
+## Step 4 - the model generates a final answer based on the tool results
+Finally, the developer calls the Cohere model, providing the tools results, in order to generate the model's final answer.
+
+Bonus: At Cohere, all Tool Use calls come with... **precise citations**! 🎉
+The model cites which tool results were used to generate the final answer.
+These citations make it easy to check where the model’s generated response claims are coming from.
+They help users gain visibility into the model reasoning, and sanity check the final model generation.
+These citations are optional — you can decide to ignore them.
+
-## Step 4 - The model generates a final answer based on the tool results
-Finally, the developer calls the Cohere model, providing the tools results, in order to generate the model's final answer.
-```python PYTHON
+```python
response = co.chat(
message=message,
tools=tools,
@@ -285,57 +330,58 @@ response = co.chat(
)
```
-```python PYTHON
+
+```python
print("Final answer:")
print(response.text)
```
-```
-Final answer:
-On the 29th of September 2023, there were 10,000 sales with 250 units sold.
-
-The Electronics category contains three products. There are details below:
-
-| Product Name | Price | Stock Level |
-| ------------ | ----- | ----------- |
-| Smartphone | 500 | 20 |
-| Laptop | 1000 | 15 |
-| Tablet | 300 | 25 |
+ Final answer:
+ On the 29th of September 2023, there were 10,000 sales with 250 units sold.
+
+ The Electronics category contains three products. There are details below:
+
+ | Product Name | Price | Stock Level |
+ | ------------ | ----- | ----------- |
+ | Smartphone | 500 | 20 |
+ | Laptop | 1000 | 15 |
+ | Tablet | 300 | 25 |
+
+ The total stock level for Electronics items is 50.
-The total stock level for Electronics items is 50.
-```
## Bonus: Citations come for free with Cohere! 🎉
-At Cohere, model generations come with... precise citations! 🎉
+At Cohere, model generations come with... precise citations! 🎉
The model cites which groups of words, in the tool results, were used to generate the final answer.
These citations make it easy to check where the model’s generated response claims are coming from.
They help users gain visibility into the model reasoning, and sanity check the final model generation.
These citations are optional — you can decide to ignore them.
-```python PYTHON
+
+```python
print("Citations that support the final answer:")
for cite in response.citations:
print(cite)
```
-```
-Citations that support the final answer:
-{'start': 7, 'end': 29, 'text': '29th of September 2023', 'document_ids': ['query_daily_sales_report:0:0']}
-{'start': 42, 'end': 75, 'text': '10,000 sales with 250 units sold.', 'document_ids': ['query_daily_sales_report:0:0']}
-{'start': 112, 'end': 127, 'text': 'three products.', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 234, 'end': 244, 'text': 'Smartphone', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 247, 'end': 250, 'text': '500', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 253, 'end': 255, 'text': '20', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 260, 'end': 266, 'text': 'Laptop', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 269, 'end': 273, 'text': '1000', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 276, 'end': 278, 'text': '15', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 283, 'end': 289, 'text': 'Tablet', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 292, 'end': 295, 'text': '300', 'document_ids': ['query_product_catalog:1:0']}
-{'start': 298, 'end': 300, 'text': '25', 'document_ids': ['query_product_catalog:1:0']}
-```
+ Citations that support the final answer:
+ {'start': 7, 'end': 29, 'text': '29th of September 2023', 'document_ids': ['query_daily_sales_report:0:0']}
+ {'start': 42, 'end': 75, 'text': '10,000 sales with 250 units sold.', 'document_ids': ['query_daily_sales_report:0:0']}
+ {'start': 112, 'end': 127, 'text': 'three products.', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 234, 'end': 244, 'text': 'Smartphone', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 247, 'end': 250, 'text': '500', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 253, 'end': 255, 'text': '20', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 260, 'end': 266, 'text': 'Laptop', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 269, 'end': 273, 'text': '1000', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 276, 'end': 278, 'text': '15', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 283, 'end': 289, 'text': 'Tablet', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 292, 'end': 295, 'text': '300', 'document_ids': ['query_product_catalog:1:0']}
+ {'start': 298, 'end': 300, 'text': '25', 'document_ids': ['query_product_catalog:1:0']}
-```python PYTHON
+
+
+```python
def insert_citations_in_order(text, citations):
"""
A helper function to pretty print citations.
@@ -376,32 +422,38 @@ print(insert_citations_in_order(response.text, response.citations))
```
-```
-On the **29th of September 2023**[1], there were **10,000 sales with 250 units sold.**[1]
+ On the **29th of September 2023**[1], there were **10,000 sales with 250 units sold.**[1]
+
+ The Electronics category contains **three products.**[2] There are details below:
+
+ | Product Name | Price | Stock Level |
+ | ------------ | ----- | ----------- |
+ | **Smartphone**[2] | **500**[2] | **20**[2] |
+ | **Laptop**[2] | **1000**[2] | **15**[2] |
+ | **Tablet**[2] | **300**[2] | **25**[2] |
+
+ The total stock level for Electronics items is 50.
+
+ [1] source: [{'date': '2023-09-29', 'summary': 'Total Sales Amount: 10000, Total Units Sold: 250'}]
+ based on tool call: {'name': 'query_daily_sales_report', 'parameters': {'day': '2023-09-29'}, 'generation_id': 'eaf955e3-623d-4796-bf51-23b07c66ed2c'}
+ [2] source: [{'category': 'Electronics', 'products': [{'product_id': 'E1001', 'name': 'Smartphone', 'price': 500, 'stock_level': 20}, {'product_id': 'E1002', 'name': 'Laptop', 'price': 1000, 'stock_level': 15}, {'product_id': 'E1003', 'name': 'Tablet', 'price': 300, 'stock_level': 25}]}]
+ based on tool call: {'name': 'query_product_catalog', 'parameters': {'category': 'Electronics'}, 'generation_id': 'eaf955e3-623d-4796-bf51-23b07c66ed2c'}
-The Electronics category contains **three products.**[2] There are details below:
-| Product Name | Price | Stock Level |
-| ------------ | ----- | ----------- |
-| **Smartphone**[2] | **500**[2] | **20**[2] |
-| **Laptop**[2] | **1000**[2] | **15**[2] |
-| **Tablet**[2] | **300**[2] | **25**[2] |
+Yiha. You've used Cohere for Tool Use. Tool use opens up a wide range of new use cases. Here are a few examples:
-The total stock level for Electronics items is 50.
+- **Function calling**: It's now possible to ask the model to output a JSON object with specific function parameters.
+For instance, this allows your chatbot to interact with your CRM to change the status of a deal, or to engage with a Python interpreter to conduct data science analyses.
-[1] source: [{'date': '2023-09-29', 'summary': 'Total Sales Amount: 10000, Total Units Sold: 250'}]
- based on tool call: {'name': 'query_daily_sales_report', 'parameters': {'day': '2023-09-29'}, 'generation_id': 'eaf955e3-623d-4796-bf51-23b07c66ed2c'}
-[2] source: [{'category': 'Electronics', 'products': [{'product_id': 'E1001', 'name': 'Smartphone', 'price': 500, 'stock_level': 20}, {'product_id': 'E1002', 'name': 'Laptop', 'price': 1000, 'stock_level': 15}, {'product_id': 'E1003', 'name': 'Tablet', 'price': 300, 'stock_level': 25}]}]
- based on tool call: {'name': 'query_product_catalog', 'parameters': {'category': 'Electronics'}, 'generation_id': 'eaf955e3-623d-4796-bf51-23b07c66ed2c'}
-```
+- **Query transformation**: You can transform a user message into a search query for a vector database or any search engine.
+For instance, this enables your work assistant to automatically retrieve the appropriate data from your company's documentation by creating the right query for your vector database.
-Now, you've used Cohere for Tool Use. Tool use opens up a wide range of new use cases. Here are a few examples:
+- **Advanced searches**: You can transform a user message into one-or-many queries, to do multiple subtasks based on the content of the message.
+For instance, this allows your chatbot to search across different databases and platforms to retrieve relevant information or to conduct comparative analysis.
-- **Function calling**: It's now possible to ask the model to output a JSON object with specific function parameters.
- For instance, this allows your chatbot to interact with your CRM to change the status of a deal, or to engage with a Python interpreter to conduct data science analyses.
-- **Query transformation**: You can transform a user message into a search query for a vector database or any search engine.
- For instance, this enables your work assistant to automatically retrieve the appropriate data from your company's documentation by creating the right query for your vector database.
-- **Advanced searches**: You can transform a user message into one-or-many queries, to do multiple subtasks based on the content of the message.
- For instance, this allows your chatbot to search across different databases and platforms to retrieve relevant information or to conduct comparative analysis.
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/calendar-agent.mdx b/fern/pages/cookbooks/calendar-agent.mdx
index 30cb01a51..1254dd9c7 100644
--- a/fern/pages/cookbooks/calendar-agent.mdx
+++ b/fern/pages/cookbooks/calendar-agent.mdx
@@ -3,22 +3,27 @@ title: Calendar Agent with Native Multi Step Tool
slug: /page/calendar-agent
description: "This page describes how to use cohere Chat API with list_calendar_events and create_calendar_event tools to book appointments."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI agents"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
In the example below, we demonstrate how to use the cohere Chat API with the `list_calendar_events` and `create_calendar_event` tools to book appointments. Booking the correct appointment requires the model to first check for an available slot by listing existing events, reasoning about the correct slot to book the new appointment and then finally invoking the right tool to create the calendar event. To learn more about Tool Use, read the official [multi-step tool use guide](https://docs.cohere.com/docs/multi-step-tool-use).
-```python PYTHON
+
+```python
# !pip install cohere==5.5.3
```
-```python PYTHON
+
+```python
# Instantiate the Cohere client
import cohere
@@ -28,7 +33,8 @@ COHERE_API_KEY = os.environ["COHERE_API_KEY"]
co = cohere.Client(api_key=COHERE_API_KEY)
```
-```python PYTHON
+
+```python
# Define the tools
import json
@@ -95,7 +101,8 @@ def invoke_tool(tool_call: cohere.ToolCall):
raise f"Unknown tool name '{tool_call.name}'"
```
-```python PYTHON
+
+```python
# Check what tools the model wants to use and how to use them
res = co.chat(
model="command-r-plus",
@@ -125,10 +132,9 @@ while res.tool_calls:
print(res.text) # print the final answer
```
-```txt title="Output"
-I will check the user's calendar for today after 3pm and book an hour-long appointment in the first available slot.
-Listing events: [{"start": "14:00", "end": "15:00"}, {"start": "15:00", "end": "16:00"}, {"start": "17:00", "end": "18:00"}]
-The user has events scheduled from 2pm to 4pm and from 5pm to 6pm. I will book an hour-long appointment from 4pm to 5pm.
-Creating a 1 hour long event at 16:00 on 05/23/2024
-I've booked an hour-long appointment for you today from 4pm to 5pm.
-```
+ I will check the user's calendar for today after 3pm and book an hour-long appointment in the first available slot.
+ Listing events: [{"start": "14:00", "end": "15:00"}, {"start": "15:00", "end": "16:00"}, {"start": "17:00", "end": "18:00"}]
+ The user has events scheduled from 2pm to 4pm and from 5pm to 6pm. I will book an hour-long appointment from 4pm to 5pm.
+ Creating a 1 hour long event at 16:00 on 05/23/2024
+ I've booked an hour-long appointment for you today from 4pm to 5pm.
+
diff --git a/fern/pages/cookbooks/chunking-strategies.mdx b/fern/pages/cookbooks/chunking-strategies.mdx
index 1e8bd7f2c..216c1e2b6 100644
--- a/fern/pages/cookbooks/chunking-strategies.mdx
+++ b/fern/pages/cookbooks/chunking-strategies.mdx
@@ -1,9 +1,9 @@
---
-title: Effective Chunking Strategies for RAG
+title: Chunking Strategies
slug: /page/chunking-strategies
description: "This page describes various chunking strategies you can use to get better RAG performance."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG"
---
@@ -14,14 +14,18 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Ania Bialas",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/c5dc5a3-Ania.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/c5dc5a3-Ania.jpg"
+ }
]}
/>
-
-```python PYTHON
+
+
+*
*
+
+
+```python
%%capture
!pip install cohere
!pip install -qU langchain-text-splitters
@@ -29,7 +33,8 @@ import { CookbookHeader } from "../../components/cookbook-header";
!pip install llama-index-postprocessor-cohere-rerank
```
-```python PYTHON
+
+```python
import requests
from typing import List
@@ -48,67 +53,99 @@ from llama_index.postprocessor.cohere_rerank import CohereRerank
from llama_index.core import VectorStoreIndex, ServiceContext
```
-```python PYTHON
+
+```python
co_model = 'command-r'
co_api_key = getpass("Enter Cohere API key: ")
co = cohere.Client(api_key=co_api_key)
```
-```txt title="Output"
-Enter Cohere API key: ··········
-```
+ Enter Cohere API key: ··········
+
-## Introduction
+
+# Introduction
Chunking is an essential component of any RAG-based system. This cookbook aims to demonstrate how different chunking strategies affect the results of LLM-generated output. There are multiple considerations that need to be taken into account when designing chunking strategy. Therefore, we begin by providing a framework for these strategies and then jump into a practical example. We will focus our example on transcript calls, which create a unique challenge because of their rich content and the change of people speaking throughout the text.
-## Chunking strategies framework [#chunking-strategies-framework]
+# Table of content
-### Document splitting
+1. [Chunking Strategies Framework](#framework)
+2. [Getting started](#getting-started)
+3. [Example 1: Chunking using content-independent strategies](#example-1)
+4. [Example 2: Chunking using content-dependent strategies](#example-2)
+5. [Discussion](#discussion)
-By document splitting, we mean deciding on the conditions under which we will break the text. At this stage, we should ask, _"Are there any parts of consecutive text we want to ensure we do not break?"_. If the answer is "no", then, the content-independent splitting strategies are helpful. On the other hand, in scenarios like transcripts or meeting notes, we probably would like to keep the content of one speaker together, which might require us to deploy content-dependent strategies.
+
+# Chunking Strategies Framework
-#### Content-independent splitting strategies
+## Document splitting
-We split the document based on some content-independent conditions, among the most popular ones are:
+By document splitting, we mean deciding on the conditions under which we will break the text. At this stage, we should ask, *"Are there any parts of consecutive text we want to ensure we do not break?"*. If the answer is "no", then, the content-independent splitting strategies are helpful. On the other hand, in scenarios like transcripts or meeting notes, we probably would like to keep the content of one speaker together, which might require us to deploy content-dependent strategies.
+### Content-independent splitting strategies
+
+We split the document based on some content-independent conditions, among the most popular ones are:
- splitting by the number of characters,
- splitting by sentence,
- splitting by a given character, for example, `\n` for paragraphs.
The advantage of this scenario is that we do not need to make any assumptions about the text. However, some considerations remain, like whether we want to preserve some semantic structure, for example, sentences or paragraphs. Sentence splitting is better suited if we are looking for small chunks to ensure accuracy. Conversely, paragraphs preserve more context and might be more useful in open-ended questions.
-#### Content-dependent splitting strategies
+### Content-dependent splitting strategies
On the other hand, there are scenarios in which we care about preserving some text structure. Then, we develop custom splitting strategies based on the document's content. A prime example is call transcripts. In such scenarios, we aim to ensure that one person's speech is fully contained within a chunk.
-### Creating chunks from the document splits
+## Creating chunks from the document splits
After the document is split, we need to decide on the desired **size** of our chunks (the split only defines how we break the document, but we can create bigger chunks from multiple splits).
Smaller chunks support more accurate retrieval. However, they might lack context. On the other hand, larger chunks offer more context, but they reduce the effectiveness of the retrieval. It is important to experiment with different settings to find the optimal balance.
-### Overlapping chunks
+## Overlapping chunks
Overlapping chunks is a useful technique to have in the toolbox. Especially when we employ content-independent splitting strategies, it helps us mitigate some of the pitfalls of breaking the document without fully understanding the text. Overlapping guarantees that there is always some buffer between the chunks, and even if an important piece of information might be split in the original splitting strategy, it is more probable that the full information will be captured in the next chunk. The disadvantage of this method is that it creates redundancy.
-## Getting started [#getting-started]
+
+# Getting started
Designing a robust chunking strategy is as much a science as an art. There are no straightforward answers; the most effective strategies often emerge through experimentation. Therefore, let's dive straight into an example to illustrate this concept.
+
+
+
+
+
+
## Utils
-```python PYTHON
+
+```python
def set_css():
display(HTML('''
-
+
'''))
get_ipython().events.register('pre_run_cell', set_css)
set_css()
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
def insert_citations(text: str, citations: List[dict]):
"""
A helper function to pretty print citations.
@@ -128,7 +165,7 @@ def insert_citations(text: str, citations: List[dict]):
return text
-def build_retriever(documents, top_n=5):
+def build_retreiver(documents, top_n=5):
# Create the embedding model
embed_model = CohereEmbedding(
cohere_api_key=co_api_key,
@@ -150,11 +187,22 @@ def build_retriever(documents, top_n=5):
return retriever
```
-## Load the data
+
+
+
+
+
+
+##Load the data
In this example we will work with an 2023 Tesla earning call transcript.
-```python PYTHON
+
+```python
# Get all investement memos (19) in bvp repository
url_path = 'https://www.fool.com/earnings/call-transcripts/2024/01/24/tesla-tsla-q4-2023-earnings-call-transcript/'
response = requests.get(url_path)
@@ -169,20 +217,31 @@ text = '\n\n'.join([div.get_text() for div in target_divs])
print(text[:500])
```
-```txt title="Output"
-Length of the script: 385
-Example of processed text:
-Martin Viecha
-Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
+
-During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions and
-```
-## Example 1: Chunking using content-independent strategies [#example-1]
-Let's begin with a simple content-independent strategy. We aim to answer the question, `Who mentions Jonathan Nolan?`. We chose this question as it is easily verifiable and it requires to identify the speaker. The answer to this question can be found in the downloaded transcript, here is the relevant passage:
+ Length of the script: 385
+
+ Example of processed text:
+ Martin Viecha
+
+ Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
+
+ During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions and
+
+
+
+# Example 1: Chunking using content-independent strategies
+
+Let's begin with a simple content-independent strategy. We aim to answer the question, `Who mentiones Jonathan Nolan?`. We chose this question as it is easily verifiable and it requires to identify the speaker. The answer to this questions can be found in the dowloaded transcscript, here is the relevant passage:
+
```
Elon Musk -- Chief Executive Officer and Product Architect
@@ -190,16 +249,28 @@ Elon Musk -- Chief Executive Officer and Product Architect
Yeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.
```
-```python PYTHON
+
+```python
# Define the question
-question = "Who mentions Jonathan Nolan?"
+question = "Who mentiones Jonathan Nolan?"
```
+
+
+
+
+
+
In this case, we are more concerned about accuracy than a verbose answer, so we **focus on keeping the chunks small**. To ensure that the desired size is not exceeded, we will randomly split the list of characters, in our case `["\n\n", "\n", " ", ""]`.
We employ the `RecursiveCharacterTextSplitter` from [LangChain](https://python.langchain.com/docs/get_started/introduction) for this task.
-```python PYTHON
+
+```python
# Define the chunking function
def get_chunks(text, chunk_size, chunk_overlap):
text_splitter = RecursiveCharacterTextSplitter(
@@ -215,17 +286,27 @@ def get_chunks(text, chunk_size, chunk_overlap):
return documents
```
-### Experiment 1 - no overlap
+
+
+
+
+
+### Experiment 1 - no overlap
In our first experiment we define the chunk size as 500 and allow **no overlap between consecutive chunks**.
Subsequently, we implement the standard RAG pipeline. We feed the chunks into a retriever, selecting the `top_n` most pertinent to the query chunks, and supply them as context to the generation model. Throughout this pipeline, we leverage [Cohere's endpoints](https://docs.cohere.com/reference/about), specifically, `co.embed`, `co.re.rank`, and finally, `co.chat`.
-```python PYTHON
+
+```python
chunk_size = 500
chunk_overlap = 0
documents = get_chunks(text, chunk_size, chunk_overlap)
-retriever = build_retriever(documents)
+retriever = build_retreiver(documents)
source_nodes = retriever.retrieve(question)
print('Number of docuemnts: ',len(source_nodes))
@@ -241,42 +322,71 @@ response = response
print(response.text)
```
-```txt title="Output"
-Number of docuemnts: 5
-An unknown speaker mentions Jonathan Nolan in a conversation about the creators of Westworld. They mention that Jonathan Nolan and Lisa Joy Nolan are friends of theirs, and that they have invited them to visit the lab.
-```
+
+
+
+
+
+
+ Number of docuemnts: 5
+ An unknown speaker mentions Jonathan Nolan in a conversation about the creators of Westworld. They mention that Jonathan Nolan and Lisa Joy Nolan are friends of theirs, and that they have invited them to visit the lab.
+
A notable feature of [`co.chat`](https://docs.cohere.com/reference/chat) is its ability to ground the model's answer within the context. This means we can identify which chunks were used to generate the answer. Below, we show the previous output of the model together with the citation reference, where `[num]` represents the index of the chunk.
-```python PYTHON
+
+```python
print(insert_citations(response.text, response.citations))
```
-```txt title="Output"
-An unknown speaker [0] mentions Jonathan Nolan in a conversation about the creators of Westworld. [0] They mention that Jonathan Nolan and Lisa Joy Nolan [0] are friends [0] of theirs, and that they have invited them to visit the lab. [0]
-```
+
+
+
+
+
+
+ An unknown speaker [0] mentions Jonathan Nolan in a conversation about the creators of Westworld. [0] They mention that Jonathan Nolan and Lisa Joy Nolan [0] are friends [0] of theirs, and that they have invited them to visit the lab. [0]
+
Indeed, by printing the cited chunk, we can validate that the text was divided so that the generation model could not provide the correct response. Notably, the speaker's name is not included in the context, which is why the model refes to an `unknown speaker`.
-```python PYTHON
+
+```python
print(source_nodes[0])
```
-```python title="Output"
-{'text': "Yeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\n\nYeah.\n\nUnknown speaker\n\nWe're not entering Westworld anytime soon."}
-```
-### Experiment 2 - allow overlap
+
+
+
+
+ {'text': "Yeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\n\nYeah.\n\nUnknown speaker\n\nWe're not entering Westworld anytime soon."}
+
+
+### Experiment 2 - allow overlap
In the previous experiment, we discovered that the chunks were generated in a way that made it impossible to generate the correct answer. The name of the speaker was not included in the relevant chunk.
Therefore, this time to mitigate this issue, we **allow for overlap between consecutive chunks**.
-```python PYTHON
+
+```python
chunk_size = 500
chunk_overlap = 100
documents = get_chunks(text,chunk_size, chunk_overlap)
-retriever = build_retriever(documents)
+retriever = build_retreiver(documents)
source_nodes = retriever.retrieve(question)
print('Number of docuemnts: ',len(source_nodes))
@@ -292,36 +402,72 @@ response = response
print(response.text)
```
-```txt title="Output"
-Number of docuemnts: 5
-Elon Musk mentions Jonathan Nolan. Musk is the CEO and Product Architect of the lab that resembles the set of Westworld, a show created by Jonathan Nolan and Lisa Joy Nolan.
-```
+
+
+
+
+
+
+ Number of docuemnts: 5
+ Elon Musk mentions Jonathan Nolan. Musk is the CEO and Product Architect of the lab that resembles the set of Westworld, a show created by Jonathan Nolan and Lisa Joy Nolan.
+
Again, we can print the text along with the citations.
-```python PYTHON
+
+```python
print(insert_citations(response.text, response.citations))
```
-```txt title="Output"
-Elon Musk [0] mentions Jonathan Nolan. Musk is the CEO and Product Architect [0] of the lab [0] that resembles the set of Westworld [0], a show created by Jonathan Nolan [0] and Lisa Joy Nolan. [0]
-```
+
+
+
+
+
+
+ Elon Musk [0] mentions Jonathan Nolan. Musk is the CEO and Product Architect [0] of the lab [0] that resembles the set of Westworld [0], a show created by Jonathan Nolan [0] and Lisa Joy Nolan. [0]
+
And investigate the chunks which were used as context to answer the query.
-```python PYTHON
+
+
+
+```python
source_nodes[0]
```
-```python title="Output"
-{'text': "Yeah, not the best reference.\n\nElon Musk -- Chief Executive Officer and Product Architect\n\nYeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\n\nYeah."}
-```
+
+
+
+
+
+
+
+
+
+ {'text': "Yeah, not the best reference.\n\nElon Musk -- Chief Executive Officer and Product Architect\n\nYeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\n\nYeah."}
+
+
As we can see, by allowing overlap we managed to get the correct answer to our question.
-## Example 2: Chunking using content-dependent strategies [#example-2]
+
+# Example 2: Chunking using content-dependent strategies
-In the previous experiment, we provided an example of how using or not using overlapping can affect a model's performance, particularly in documents such as call transcripts where subjects change frequently. Ensuring that each chunk contains all relevant information is crucial. While we managed to retrieve the correct information by introducing overlapping into the chunking strategy, this might still not be the optimal approach for transcripts with longer speaker speeches.
+In the previous experiment, we provided an example of how using or not using overlapping can affect a model's performance, particularly in documents such as call transcripts where subjects change frequently. Ensuring that each chunk contains all relevant information is crucial. While we managed to retrieve the correct information by introducing overlapping into the chunking strategy, this might still not be the optimal approach for transcripts with longer speaker speeches.
Therefore, in this experiment, we will adopt a content-dependent strategy.
@@ -329,11 +475,12 @@ Our proposed approach entails segmenting the text whenever a new speaker begins
### Preprocess the text
-Firstly, let's observe that in the HTML text, each time the speaker changes, their name is enclosed within `Name
` tags, denoting the speaker's name in bold letters.
+Firstly, let's observe that in the HTML text, each time the speaker changes, their name is enclosed within `Name
` tags, denoting the speaker's name in bold letters.
To facilitate our text chunking process, we'll use the above observation and introduce a unique character sequence `###`, which we'll utilize as a marker for splitting the text.
-```python PYTHON
+
+```python
print('HTML text')
print(target_divs[:3])
print('-------------------\n')
@@ -351,19 +498,29 @@ text_custom = '\n'.join(text_custom)
print(text_custom[:500])
```
-```txt title="Output"
-HTML text
-[Martin Viecha
, Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
, During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions and expectations as of today. Actual events or results could differ materially due to a number of risks and uncertainties, including those mentioned in our most recent filings with the SEC. [Operator instructions] But before we jump into Q&A, Elon has some opening remarks.
]
--------------------
-### Martin Viecha
-Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
-During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions an
-```
+
+
+
+
+
+ HTML text
+ [Martin Viecha
, Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
, During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions and expectations as of today. Actual events or results could differ materially due to a number of risks and uncertainties, including those mentioned in our most recent filings with the SEC. [Operator instructions] But before we jump into Q&A, Elon has some opening remarks.
]
+ -------------------
+
+ ### Martin Viecha
+ Good afternoon, everyone, and welcome to Tesla's fourth-quarter 2023 Q&A webcast. My name is Martin Viecha, VP of investor relations, and I'm joined today by Elon Musk, Vaibhav Taneja, and a number of other executives. Our Q4 results were announced at about 3 p.m. Central Time in the update that we published at the same link as this webcast.
+ During this call, we will discuss our business outlook and make forward-looking statements. These comments are based on our predictions an
+
In this approach, we prioritize splitting the text at the appropriate separator, `###.` To ensure this behavior, we'll use `CharacterTextSplitter` from [LangChain](https://python.langchain.com/docs/get_started/introduction), guaranteeing such behavior. From our analysis of the text and the fact that we aim to preserve entire speaker speeches intact, we anticipate that most of them will exceed a length of 500. Hence, we'll increase the chunk size to 1000.
-```python PYTHON
+
+```python
separator = "###"
chunk_size = 1000
chunk_overlap = 0
@@ -379,7 +536,7 @@ text_splitter = CharacterTextSplitter(
documents = text_splitter.create_documents([text_custom])
documents = [Document(text=doc.page_content) for doc in documents]
-retriever = build_retriever(documents)
+retriever = build_retreiver(documents)
source_nodes = retriever.retrieve(question)
print('Number of docuemnts: ',len(source_nodes))
@@ -394,41 +551,75 @@ response = response
print(response.text)
```
-```txt title="Output"
-WARNING:langchain_text_splitters.base:Created a chunk of size 5946, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 4092, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1782, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1392, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 2046, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1152, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1304, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1295, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 2090, which is longer than the specified 1000
-WARNING:langchain_text_splitters.base:Created a chunk of size 1251, which is longer than the specified 1000
-
-
-Number of docuemnts: 5
-Elon Musk mentions Jonathan Nolan. Musk is friends with the creators of Westworld, Jonathan Nolan and Lisa Joy Nolan.
-```
+
+
+
+
+
+
+ WARNING:langchain_text_splitters.base:Created a chunk of size 5946, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 4092, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1782, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1392, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 2046, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1152, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1304, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1295, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 2090, which is longer than the specified 1000
+ WARNING:langchain_text_splitters.base:Created a chunk of size 1251, which is longer than the specified 1000
+
+
+ Number of docuemnts: 5
+ Elon Musk mentions Jonathan Nolan. Musk is friends with the creators of Westworld, Jonathan Nolan and Lisa Joy Nolan.
+
Below we validate the answer using citations.
-```python PYTHON
+
+```python
print(insert_citations(response.text, response.citations))
```
-```txt title="Output"
-Elon Musk [0] mentions Jonathan Nolan. [0] Musk is friends [0] with the creators of Westworld [0], Jonathan Nolan [0] and Lisa Joy Nolan. [0]
-```
-```python PYTHON
+
+
+
+
+
+ Elon Musk [0] mentions Jonathan Nolan. [0] Musk is friends [0] with the creators of Westworld [0], Jonathan Nolan [0] and Lisa Joy Nolan. [0]
+
+
+
+```python
source_nodes[0]
```
-```python title="Output"
-{'text': "Elon Musk -- Chief Executive Officer and Product Architect\nYeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\nYeah.\n### Unknown speaker\nWe're not entering Westworld anytime soon.\n### Elon Musk -- Chief Executive Officer and Product Architect\nRight, right. Yeah. I take -- take safety very very seriously.\n### Martin Viecha\nThank you. The next question from Norman is: How many Cybertruck orders are in the queue? And when do you anticipate to be able to fulfill existing orders?"}
-```
-## Discussion [#discussion]
+
+
+
+
+
+
+
+
+ {'text': "Elon Musk -- Chief Executive Officer and Product Architect\nYeah. The creators of Westworld, Jonathan Nolan, Lisa Joy Nolan, are friends -- are all friends of mine, actually. And I invited them to come see the lab and, like, well, come see it, hopefully soon. It's pretty well -- especially the sort of subsystem test stands where you've just got like one leg on a test stand just doing repetitive exercises and one arm on a test stand pretty well.\nYeah.\n### Unknown speaker\nWe're not entering Westworld anytime soon.\n### Elon Musk -- Chief Executive Officer and Product Architect\nRight, right. Yeah. I take -- take safety very very seriously.\n### Martin Viecha\nThank you. The next question from Norman is: How many Cybertruck orders are in the queue? And when do you anticipate to be able to fulfill existing orders?"}
+
+
+
+
+# Discussion
This example highlights some of the concerns that arise when implementing chunking strategies. This is a field of ongoing research, and many exciting surveys have been published in domain-specific applications. For example, this [paper](https://arxiv.org/pdf/2402.05131.pdf) examines different chunking strategies in finance.
diff --git a/fern/pages/cookbooks/creating-a-qa-bot.mdx b/fern/pages/cookbooks/creating-a-qa-bot.mdx
index 6c67acecb..fb50a01a2 100644
--- a/fern/pages/cookbooks/creating-a-qa-bot.mdx
+++ b/fern/pages/cookbooks/creating-a-qa-bot.mdx
@@ -3,34 +3,41 @@ title: Creating a QA Bot From Technical Documentation
slug: /page/creating-a-qa-bot
description: "This page describes how to use Cohere to build a simple question-answering system."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI agents, question answering systems"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
This notebook demonstrates how to create a chatbot (single turn) that answers user questions based on technical documentation made available to the model.
We use the `aws-documentation` dataset ([link](https://github.com/siagholami/aws-documentation/tree/main)) for representativeness. This dataset contains 26k+ AWS documentation pages, preprocessed into 120k+ chunks, and 100 questions based on real user questions.
We proceed as follows:
-
-1. Embed the AWS documentation into a vector database using Cohere embeddings and `llama_index`
+1. Embed the AWS documentation into a vector database using Cohere's `embed` model and `llama_index`
2. Build a retriever using Cohere's `rerank` for better accuracy, lower inference costs and lower latency
-3. Create model answers for the eval set of 100 questions
-4. Evaluate the model answers against the golden answers of the eval set
+3. Create model answers for the eval set of 100 questions using Cohere's `command-r` model
+4. Evaluate the generated answers against the golden answers of the eval set using `command-r+`, Cohere's most capable generative model as a judge
+
## Setup
-```python PYTHON
+
+```python
%%capture
!pip install cohere datasets llama_index llama-index-llms-cohere llama-index-embeddings-cohere
```
-```python PYTHON
+
+```python
+import os
+import random
import cohere
import datasets
from llama_index.core import StorageContext, VectorStoreIndex, load_index_from_storage
@@ -43,76 +50,129 @@ from pathlib import Path
from tqdm import tqdm
from typing import List
+from dotenv import load_dotenv
+load_dotenv()
+
+import warnings
+warnings.filterwarnings('ignore')
+
```
-```python PYTHON
-api_key = "" #
-co = cohere.Client(api_key=api_key)
+
+```python
+# Set up Cohere client
+api_key = "" #
+# Setup Cohere client with experiment logging disabled (for JSON structured output)
+co = cohere.Client(api_key=api_key, log_warning_experimental_features=False)
+
+stub_len = len("https://github.com/siagholami/aws-documentation/tree/main/documents/")
```
## 1. Embed technical documentation and store as vector database
-- Load the dataset from HuggingFace
-- Compute embeddings using Cohere's implementation in LlamaIndex, `CohereEmbedding`
-- Store inside a vector database, `VectorStoreIndex` from LlamaIndex
+* Load the dataset from HuggingFace
+* Compute embeddings using Cohere's implementation in LlamaIndex, `CohereEmbedding`
+* Store inside a vector database, `VectorStoreIndex` from LlamaIndex
+
+
+Because this process is lengthy (~2h for all documents on a MacBookPro), we store the index to disc for future reuse. We also provide an option to to index only a subset of the data. This can be enabled by setting the value of the variable `USE_SNIPPET` to `True` in the block below. If you use this option, bear in mind that many documents will become unavailable to the model and, as a result, performance will suffer!
-Because this process is lengthy (~2h for all documents on a MacBookPro), we store the index to disc for future reuse. We also provide a (commented) code snippet to index only a subset of the data. If you use this snippet, bear in mind that many documents will become unavailable to the model and, as a result, performance will suffer!
-```python PYTHON
+```python
+# Set to true if you want to use only a small sample of the training data (~10000) rows
+USE_SNIPPET = True
+
data = datasets.load_dataset("sauravjoshi23/aws-documentation-chunked")
-print(data)
+# The data comes prechunked. We keep the data as-is in this notebook.
+# For more information on optimal preprocessing strategies, please check
+# our other notebooks!
-map_id2index = {sample["id"]: index for index, sample in enumerate(data["train"])}
+# Add a column with the shortened source. This will be used to cross-reference with the QA Evaluation dataset to ensure
+# that the relevant testing data sources are captured in the smaller samples of data selected
+if USE_SNIPPET:
+ data = data.map(lambda x: {"short_source": x["source"][stub_len:].replace("/doc_source", "")})
-```
+# Build a mapping from sample id to index inside data (will be useful for retrieval later)
+map_id2index = {sample["id"]: index for index, sample in enumerate(data["train"])}
-```txt title="Output"
-/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:88: UserWarning:
-The secret `HF_TOKEN` does not exist in your Colab secrets.
-To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.
-You will be able to reuse this secret in all of your notebooks.
-Please note that authentication is recommended but still optional to access public models or datasets.
- warnings.warn(
+print(data["train"])
+```
-DatasetDict({
- train: Dataset({
- features: ['id', 'text', 'source'],
+ Dataset({
+ features: ['id', 'text', 'source', 'short_source'],
num_rows: 187147
})
-})
+
+
+To assess the performance of our RAG pipeline, we will also need some QA pairs to validate the answers generated by `command`. The author of the repository above provides 100 QA pairs that we can test the model on. Let's download these questions.
+
+**NOTE**: if you have set `USE_SNIPPET` to `True`, the following block also creates a separate copy of the dataset with documents that the QA pairs test on, so that we can ensure that these particular documents are always included as a subset in the smaller sampled training set.
+
+
+```python
+# Load data from github
+url = "https://github.com/siagholami/aws-documentation/blob/main/QA_true.csv?raw=true"
+qa_pairs = pd.read_csv(url)
+
+# Filters and extracts the rows in the data that correspond with documents that are referenced
+# in the QA pairs test set
+if USE_SNIPPET:
+ golden_docs = qa_pairs['Document_True'].tolist()
+ golden_doc_data = data.filter(lambda x: x['short_source'] in golden_docs)
```
-```python PYTHON
-overwrite = True # only compute index if it doesn't exist
+```python
+# Create index in vector database, and persist it for later reuse
+# Note: this cell takes about ~2h on a MacBookPro
+
+overwrite = False # only compute index if it doesn't exist
path_index = Path(".") / "aws-documentation_index_cohere"
+# Select Cohere's new `embed-english-v3.0` as the engine to compute embeddings
embed_model = CohereEmbedding(
cohere_api_key=api_key,
model_name="embed-english-v3.0",
)
-
+
if not path_index.exists() or overwrite:
# Documents are prechunked. Keep them as-is for now
- stub_len = len("https://github.com/siagholami/aws-documentation/tree/main/documents/")
- documents = [
- # -- for indexing full dataset --
- TextNode(
- text=sample["text"],
- title=sample["source"][stub_len:], # save source minus stub
- id_=sample["id"],
- ) for sample in data["train"]
- # -- for testing on subset --
- # TextNode(
- # text=data["train"][index]["text"],
- # title=data["train"][index]["source"][stub_len:],
- # id_=data["train"][index]["id"],
- # ) for index in range(1_000)
- ]
+ # -- for indexing on a subset of full dataset --
+ if USE_SNIPPET:
+ documents = [
+ TextNode(
+ text=data["train"][index]["text"],
+ title=data["train"][index]["source"][stub_len:],
+ id_=data["train"][index]["id"],
+ ) for index in range(5_000)
+ ]
+ # Extend the sample of documents with the documents referenced in the QA pairs
+ # test set
+ documents.extend(
+ [
+ TextNode(
+ text=data["text"],
+ title=data["source"][stub_len:],
+ id_=data["id"],
+ ) for data in golden_doc_data["train"]
+ ]
+ )
+ else:
+ documents = [
+ # -- for indexing full dataset --
+ TextNode(
+ text=sample["text"],
+ title=sample["source"][stub_len:], # save source minus stub
+ id_=sample["id"],
+ ) for sample in data["train"]
+ ]
+
+ # Shuffle nodes in documents
+ random.shuffle(documents)
+
index = VectorStoreIndex(documents, embed_model=embed_model)
index.storage_context.persist(path_index)
-
else:
storage_context = StorageContext.from_defaults(persist_dir=path_index)
index = load_index_from_storage(storage_context, embed_model=embed_model)
@@ -123,13 +183,14 @@ else:
The vector database we built using `VectorStoreIndex` comes with an in-built retriever. We can call that retriever to fetch the top $k$ documents most relevant to the user question with:
-```python PYTHON
+```python
retriever = index.as_retriever(similarity_top_k=top_k)
```
-We recently released [Rerank-3](https://cohere.com/blog/rerank-3/) (April '24), which we can use to improve the quality of retrieval, as well as reduce latency and the cost of inference. To use the retriever with `rerank`, we create a thin wrapper around `index.as_retriever` as follows:
+We recently released [Rerank-3](https://txt.cohere.com/rerank-3/) (April '24), which we can use to improve the quality of retrieval, as well as reduce latency and the cost of inference. To use the retriever with `rerank`, we create a thin wrapper around `index.as_retriever` as follows:
+
-```python PYTHON
+```python
class RetrieverWithRerank:
def __init__(self, retriever, api_key):
self.retriever = retriever
@@ -155,6 +216,7 @@ class RetrieverWithRerank:
top_k = 60 # how many documents to fetch on first pass
top_n = 20 # how many documents to sub-select with rerank
+# Instantiate retriver
retriever = RetrieverWithRerank(
index.as_retriever(similarity_top_k=top_k),
api_key=api_key,
@@ -162,19 +224,31 @@ retriever = RetrieverWithRerank(
```
-```python PYTHON
+
+```python
+# Test the retriever on a single question!
query = "What happens to my Amazon EC2 instances if I delete my Auto Scaling group?"
+# Retrieving relevant documents with rerank now fits in one line
documents = retriever.retrieve(query, top_n=top_n)
+# Call Cohere's RAG pipeline with co.chat and the `documents` argument
resp = co.chat(message=query, model="command-r", temperature=0., documents=documents)
print(resp.text)
```
+ Deleting an Auto Scaling group will stop and terminate all of your Amazon EC2 instances within that group.
+
+ However, you may want to instead stop or terminate your Amazon EC2 instances individually, especially if you no longer need them running. This can be done using alarm actions in CloudWatch.
+
+ If you want to remove an Auto Scaling group but keep your instances, you can follow the removal process described in the Amazon EC2 User Guide.
+
+
This works! With `co.chat`, you get the additional benefit that citations are returned for every span of text. Here's a simple function to display the citations inside square brackets.
-```python PYTHON
+
+```python
def build_answer_with_citations(response):
""" """
text = response.text
@@ -201,48 +275,65 @@ print(grounded_answer)
```
-## 3. Create model answers for 100 QA pairs
+ Deleting an Auto Scaling group will stop and terminate [14] all of your Amazon EC2 instances [14] within that group. [14]
+
+ However, you may want to instead stop or terminate your Amazon EC2 instances individually [6] , especially if you no longer need them running. [6] This can be done using alarm actions in CloudWatch. [6]
+
+ If you want to remove an Auto Scaling group but keep your instances [18] , you can follow the removal process described in the Amazon EC2 User Guide. [18]
-Now that we have a running pipeline, we need to assess its performance.
-The author of the repository provides 100 QA pairs that we can test the model on. Let's download these questions, then run inference on all 100 questions. Later, we will use Command-R+ -- Cohere's largest and most powerful model -- to measure performance.
+## 3. Create model answers for 100 QA pairs
-```python PYTHON
-url = "https://github.com/siagholami/aws-documentation/blob/main/QA_true.csv?raw=true"
-qa_pairs = pd.read_csv(url)
-qa_pairs.sample(2)
+Now that we have a running pipeline, we need to assess its performance.
-```
+We can now run inference on all of the QA test pairs (100 questions). Later, we will use Command-R+ -- Cohere's largest and most powerful model -- to measure performance.
We'll use the fields as follows:
-
-- `Question`: the user question, passed to `co.chat` to generate the answer
-- `Answer_True`: treat as the ground gruth; compare to the model-generated answer to determine its correctness
-- `Document_True`: treat as the (single) golden document; check the rank of this document inside the model's retrieved documents
+* `Question`: the user question, passed to `co.chat` to generate the answer
+* `Answer_True`: treat as the ground gruth; compare to the model-generated answer to determine its correctness
+* `Document_True`: treat as the (single) golden document; check the rank of this document inside the model's retrieved documents
We'll loop over each question and generate our model answer. We'll also complete two steps that will be useful for evaluating our model next:
-
1. We compute the rank of the golden document amid the retrieved documents -- this will inform how well our retrieval system performs
2. We prepare the grading prompts -- these will be sent to an LLM scorer to compute the goodness of responses
-```python PYTHON
-LLM_EVAL_TEMPLATE = """## References
+```python
+# Define the LLM eval prompt
+# We request a score and a reason for assigning that score to 'trigger CoT' and
+# improve the model response
+
+LLM_EVAL_TEMPLATE = \
+"""
+## References
{references}
QUESTION: based on the above reference documents, answer the following question: {question}
ANSWER: {answer}
STUDENT RESPONSE: {completion}
-Based on the question and answer above, grade the studen't reponse. A correct response will contain exactly \
+Based on the question (QUESTION) and answer above (ANSWER), grade the student's reponse (STUDENT RESPONSE). A correct response will contain exactly \
the same information as in the answer, even if it is worded differently. If the student's reponse is correct, \
give it a score of 1. Otherwise, give it a score of 0. Let's think step by step. Return your answer as \
as a compilable JSON with the following structure:
{{
"reasoning": ,
- "score: ,
-}}"""
-
+ "score: ,
+}}
+"""
+# Response format to enforce the model to produce a JSONic structure with its response
+# as instructed by the eval prompt above
+RESPONSE_FORMAT = {
+ "type": "json_object",
+ "schema": {
+ "type": "object",
+ "required": ["reasoning", "score"],
+ "properties": {
+ "reasoning": { "type": "string" },
+ "score": { "type": "integer"}
+ }
+ }
+}
def get_rank_of_golden_within_retrieved(golden: str, retrieved: List[dict]) -> int:
"""
@@ -260,6 +351,7 @@ def get_rank_of_golden_within_retrieved(golden: str, retrieved: List[dict]) -> i
# format as in dataset
source = source[stub_len:] # remove stub
source = source.replace("/doc_source", "") # remove /doc_source/
+
if source not in doc_to_rank:
doc_to_rank[source] = rank + 1
@@ -268,7 +360,8 @@ def get_rank_of_golden_within_retrieved(golden: str, retrieved: List[dict]) -> i
```
-```python PYTHON
+
+```python
from tqdm import tqdm
answers = []
@@ -282,7 +375,12 @@ for _, row in tqdm(qa_pairs.iterrows(), total=len(qa_pairs)):
# --- Produce answer using retriever ---
documents = retriever.retrieve(query, top_n=top_n)
- resp = co.chat(message=query, model="command-r", temperature=0., documents=documents)
+ resp = co.chat(
+ message=query,
+ model="command-r",
+ temperature=0,
+ documents=documents,
+ )
answer = resp.text
answers.append(answer)
@@ -297,22 +395,35 @@ for _, row in tqdm(qa_pairs.iterrows(), total=len(qa_pairs)):
# ^ snippet looks complicated, but all it does it unpack all kwargs from `documents`
# into text separated by \n\n
grading_prompt = LLM_EVAL_TEMPLATE.format(
- references=references_text, question=query, answer=golden_answer, completion=answer,
+ references=references_text, question=query, answer=golden_answer, completion=answer
)
grading_prompts.append(grading_prompt)
```
+ 100%|██████████| 100/100 [09:04<00:00, 5.44s/it]
+
+
+
+```python
+import pickle
+
+# Optional, to persist the grading_prompts list as a pickle object
+with open("../data/grading_prompts.pkl", "wb") as f:
+ pickle.dump(grading_prompts, f)
+```
+
## 4. Evaluate model performance
We want to test our model performance on two dimensions:
-
1. How good is the final answer? We'll compare our model answer to the golden answer using Command-R+ as a judge.
2. How good is the retrieval? We'll use the rank of the golden document within the retrieved documents to this end.
Note that this pipeline is for illustration only. To measure performance in practice, we would want to run more in-depths tests on a broader, representative dataset.
-```python PYTHON
+
+```python
+# For simplicity, prepare a DataFrame with the results
results = pd.DataFrame()
results["answer"] = answers
results["golden_answer"] = qa_pairs["Answer_True"]
@@ -324,69 +435,138 @@ results["rank"] = ranks
We'll use Command-R+ as a judge of whether the answers produced by our model convey the same information as the golden answers. Since we've defined the grading prompts earlier, we can simply ask our LLM judge to evaluate that grading prompt. After a little bit of postprocessing, we can then extract our model scores.
-````python PYTHON
+
+```python
+import pickle
+
scores = []
reasonings = []
def remove_backticks(text: str) -> str:
- """
- Some models are trained to output JSON in Markdown formatting:
- ```json {json object}```
- Remove the backticks from those model responses so that they become
- parasable by json.loads.
- """
- if text.startswith("```json"):
- text = text[7:]
- if text.endswith("```"):
- text = text[:-3]
- return text
+ """
+ Some models are trained to output JSON in Markdown formatting:
+ ```json {json object}```
+ Remove the backticks from those model responses so that they become
+ parasable by json.loads.
+ """
+ if text.startswith("```json"):
+ text = text[7:]
+ if text.endswith("```"):
+ text = text[:-3]
+ return text
+# -- uncomment to load saved grading_prompts list --
+with open("../data/grading_prompts.pkl", "rb") as f:
+ grading_prompts = pickle.load(f)
+
for prompt in tqdm(grading_prompts, total=len(grading_prompts)):
- resp = co.chat(message=prompt, model="command-r-plus", temperature=0.)
- # Convert response to JSON to extract the `score` and `reasoning` fields
- # We remove backticks for compatibility with different LLMs
- parsed = json.loads(remove_backticks(resp.text))
- scores.append(parsed["score"])
- reasonings.append(parsed["reasoning"])
+ resp = co.chat(
+ message=prompt,
+ model="command-r-plus",
+ temperature=0.,
+ response_format=RESPONSE_FORMAT,
+ )
+ # Convert response to JSON to extract the `score` and `reasoning` fields
+ # We remove backticks for compatibility with different LLMs
+ parsed = json.loads(resp.text)
+ scores.append(parsed["score"])
+ reasonings.append(parsed["reasoning"])
+
+```
+
+ 100%|██████████| 100/100 [03:43<00:00, 2.23s/it]
+
+
+
+```python
+import pickle
+
+# Optional, to persist scores and reasonings lists
+with open("../data/scores.pkl", "wb") as f:
+ pickle.dump(scores, f)
+with open("../data/reasonings.pkl", "wb") as f:
+ pickle.dump(reasonings, f)
+```
+
+
+```python
+import pickle
-````
+# -- uncomment to load saved scores, reasonings lists --
+with open("../data/scores.pkl", "rb") as f:
+ scores = pickle.load(f)
+with open("../data/reasonings.pkl", "rb") as f:
+ reasonings = pickle.load(f)
-```python PYTHON
+# Add scores to our DataFrame
results["score"] = scores
results["reasoning"] = reasonings
```
-```python PYTHON
+
+```python
+results[results["rank"] <= 5].shape[0] / results.shape[0]
+```
+
+
+
+
+ 0.99
+
+
+
+
+```python
print(f"Average score: {results['score'].mean():.3f}")
```
+ Average score: 0.970
+
+
### 4.2 Compute rank
-We've already computed the rank of the golden documents using `get_rank_of_golden_within_retrieved`. Here, we'll plot the histogram of ranks, using blue when the answer scored a 1, and red when the answer scored a 0.
+We've already computed the rank of the golden documents using `get_rank_of_golden_within_retrieved`. Here, we'll plot the histogram of ranks, using blue when the answer scored a 1
-```python PYTHON
+
+```python
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid", rc={"grid.color": ".8"})
-results["rank_shifted_left"] = results["rank"] - 0.1
-results["rank_shifted_right"] = results["rank"] + 0.1
+# Create a custom palette for score coloring
+custom_palette = {0: "red", 1: "blue"}
f, ax = plt.subplots(figsize=(5, 3))
-sns.histplot(data=results.loc[results["score"] == 1], x="rank_shifted_left", color="skyblue", label="Correct answer", binwidth=1)
-sns.histplot(data=results.loc[results["score"] == 0], x="rank_shifted_right", color="red", label="False answer", binwidth=1)
+sns.histplot(
+ data=results,
+ x="rank",
+ hue="score",
+ palette=custom_palette,
+ edgecolor="black",
+ binwidth=1
+)
ax.set_xticks([1, 5, 0, 10, 15, 20])
ax.set_title("Rank of golden document (max means golden doc. wasn't retrieved)")
ax.set_xlabel("Rank")
-ax.legend();
+
+legend = ax.get_legend()
+legend.set_title("Score")
+legend.get_title().set_fontsize('small')
+legend.get_title().set_fontweight('bold')
```
-We see that retrieval works well overall: for 80% of questions, the golden document is within the top 5 documents. However, we also notice that approx. half the false answers come from instances where the golden document wasn't retrieved (`rank = top_k = 20`). This should be improved, e.g. by adding metadata to the documents such as their section headings, or altering the chunking strategy.
+
+
+
+
+
+
+We see that retrieval works well overall: for about over 95% of questions, the golden document is consistently within the top 5 documents. However, we also notice that approx. half the false answers come from instances where the golden document wasn't retrieved (`rank = top_k = 20`). This should be improved, e.g. by adding metadata to the documents such as their section headings, or altering the chunking strategy.
There is also a non-negligible instance of false answers where the top document was retrieved. On closer inspection, many of these are due to the model phrasing its answers more verbosely than the (very laconic) golden documents. This highlights the importance of checking eval results before jumping to conclusions about model performance.
@@ -397,3 +577,10 @@ In this notebook, we've built a QA bot that answers user questions based on tech
1. How to embed the technical documentation into a vector database using Cohere embeddings and `llama_index`
2. How to build a custom retriever that leverages Cohere's `rerank`
3. How to evaluate model performance against a predetermined set of golden QA pairs
+
+
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/csv-agent-native-api.mdx b/fern/pages/cookbooks/csv-agent-native-api.mdx
index 4d71ae851..085db8081 100644
--- a/fern/pages/cookbooks/csv-agent-native-api.mdx
+++ b/fern/pages/cookbooks/csv-agent-native-api.mdx
@@ -3,7 +3,7 @@ title: Financial CSV Agent with Native Multi-Step Cohere API
slug: /page/csv-agent-native-api
description: "This page describes how to use Cohere's models and its native API to build an agent able to work with CSV data."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG, AI agents, CSV"
---
@@ -14,21 +14,22 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Jason Jung",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg"
+ }
]}
/>
-
-# Notebook Overview
+
+
+
-## Motivation
+
+## Motivation
Tabular data reasoning continues to be an exciting application of Agents, particularly in the financial domain, where multiple reasoning steps may be needed to identify the right answer. For example, a financial analyst working with financial statements may be interested in computing various financial ratios with natural language queries.
Some examples may include:
-
- ROE (Return on Equity) = Net Income / Shareholder's Equity
- Net Profit Margin = Net Income / Revenue
- Asset Turnover = Revenue / Average Total Assets
@@ -38,11 +39,25 @@ Having an Agent which is able to correctly compute these and other ratios would
## Objective
-In this notebook we explore how to setup a [Cohere Agent](https://docs.cohere.com/docs/multi-step-tool-use) to answer questions over tables in Apple's SEC10K 2020 form. [Financial CSV Agent](https://docs.cohere.com/page/csv-agent) already showed how to use Langchain to ask questions about your data. This notebook will demonstrate how you can build the same agent using Cohere's native API with Langchain Python tool. We will also explore how to make your agent more resilient to errors.
+In this notebook we explore how to setup a [Cohere Agent](https://docs.cohere.com/docs/multi-step-tool-use) to answer questions over tables in Apple's SEC10K 2020 form. [financial_csv_publication.ipynb](#TODO) already showed how to use langchain to ask questions about your data. This notebook will demonstrate how you can build the same agent using Cohere's native API with langchain python tool. We will also explore how to make your agent more resilient to errors.
+
+## Table of Contents
+
+- [Setup](#setup)
+- [Define Python Tool](#define_python_tool)
+- [Create Cohere Agent](#create_cohere_agent)
+- [QnA over Single Table](#qna_over_single_table)
+- [QnA over Multiple Tables](#qna_over_multiple_tables)
+- [Error Resilience](#error_resilience)
+ - [Add Viewing Tool](#add_viewing_tool)
+
+
+
+
+# Setup
-# Setup [#setup]
-```python PYTHON
+```python
import os
from typing import List
@@ -56,12 +71,19 @@ from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_experimental.utilities import PythonREPL
```
-```python PYTHON
+
+```python
+####################################################################################################
+#
# Uncomment if you need to install the following packages
+#
+####################################################################################################
+
# !pip install --quiet langchain langchain_experimental cohere --upgrade
```
-```python PYTHON
+
+```python
# versions
print('cohere version:', cohere.__version__)
print('langchain version:', langchain.__version__)
@@ -69,195 +91,236 @@ print('langchain_core version:', langchain_core.__version__)
print('langchain_experimental version:', langchain_experimental.__version__)
```
-```txt title="Output"
-cohere version: 5.5.1
-langchain version: 0.2.0
-langchain_core version: 0.2.0
-langchain_experimental version: 0.0.59
-```
+ cohere version: 5.5.1
+ langchain version: 0.2.0
+ langchain_core version: 0.2.0
+ langchain_experimental version: 0.0.59
+
-### API Key
+### API Key
-```python PYTHON
+
+```python
COHERE_API_KEY = os.environ["COHERE_API_KEY"]
CHAT_URL= "https://api.cohere.ai/v1/chat"
COHERE_MODEL = 'command-r-plus'
co = cohere.Client(api_key=COHERE_API_KEY)
```
-### Data Loading
+### Data Loading
+
-```python PYTHON
+```python
income_statement = pd.read_csv('income_statement.csv')
balance_sheet = pd.read_csv('balance_sheet.csv')
```
-```python PYTHON
+
+```python
income_statement.head(2)
```
+
+
+
-
-
-
- |
- Unnamed: 0 |
- index |
- RevenueFromContractWithCustomerExcludingAssessedTax |
- CostOfGoodsAndServicesSold |
- GrossProfit |
- ResearchAndDevelopmentExpense |
- SellingGeneralAndAdministrativeExpense |
- OperatingExpenses |
- OperatingIncomeLoss |
- NonoperatingIncomeExpense |
-
- IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest
- |
- IncomeTaxExpenseBenefit |
- NetIncomeLoss |
- EarningsPerShareBasic |
- EarningsPerShareDiluted |
- WeightedAverageNumberOfSharesOutstandingBasic |
- WeightedAverageNumberOfDilutedSharesOutstanding |
-
-
-
-
- 0 |
- 0 |
- 2017-10-01-2018-09-29 |
- 265595000000 |
- 1.637560e+11 |
- 101839000000 |
- 1.423600e+10 |
- 1.670500e+10 |
- 3.094100e+10 |
- 7.089800e+10 |
- 2.005000e+09 |
- 7.290300e+10 |
- 1.337200e+10 |
- 59531000000 |
- 3.00 |
- 2.98 |
- 1.982151e+10 |
- 2.000044e+10 |
-
-
- 1 |
- 1 |
- 2018-09-30-2018-12-29 |
- 84310000000 |
- NaN |
- 32031000000 |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- 19965000000 |
- 1.05 |
- 1.05 |
- NaN |
- NaN |
-
-
-
+
+
+
+
+ |
+ Unnamed: 0 |
+ index |
+ RevenueFromContractWithCustomerExcludingAssessedTax |
+ CostOfGoodsAndServicesSold |
+ GrossProfit |
+ ResearchAndDevelopmentExpense |
+ SellingGeneralAndAdministrativeExpense |
+ OperatingExpenses |
+ OperatingIncomeLoss |
+ NonoperatingIncomeExpense |
+ IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest |
+ IncomeTaxExpenseBenefit |
+ NetIncomeLoss |
+ EarningsPerShareBasic |
+ EarningsPerShareDiluted |
+ WeightedAverageNumberOfSharesOutstandingBasic |
+ WeightedAverageNumberOfDilutedSharesOutstanding |
+
+
+
+
+ 0 |
+ 0 |
+ 2017-10-01-2018-09-29 |
+ 265595000000 |
+ 1.637560e+11 |
+ 101839000000 |
+ 1.423600e+10 |
+ 1.670500e+10 |
+ 3.094100e+10 |
+ 7.089800e+10 |
+ 2.005000e+09 |
+ 7.290300e+10 |
+ 1.337200e+10 |
+ 59531000000 |
+ 3.00 |
+ 2.98 |
+ 1.982151e+10 |
+ 2.000044e+10 |
+
+
+ 1 |
+ 1 |
+ 2018-09-30-2018-12-29 |
+ 84310000000 |
+ NaN |
+ 32031000000 |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ 19965000000 |
+ 1.05 |
+ 1.05 |
+ NaN |
+ NaN |
+
+
+
-```python PYTHON
+
+
+
+```python
balance_sheet.head(2)
```
+
+
+
-
-
-
- |
- Unnamed: 0 |
- index |
- CashAndCashEquivalentsAtCarryingValue |
- MarketableSecuritiesCurrent |
- AccountsReceivableNetCurrent |
- InventoryNet |
- NontradeReceivablesCurrent |
- OtherAssetsCurrent |
- AssetsCurrent |
- MarketableSecuritiesNoncurrent |
- ... |
- LongTermDebtNoncurrent |
- OtherLiabilitiesNoncurrent |
- LiabilitiesNoncurrent |
- Liabilities |
- CommitmentsAndContingencies |
- CommonStocksIncludingAdditionalPaidInCapital |
- RetainedEarningsAccumulatedDeficit |
- AccumulatedOtherComprehensiveIncomeLossNetOfTax |
- StockholdersEquity |
- LiabilitiesAndStockholdersEquity |
-
-
-
-
- 0 |
- 0 |
- 2017-09-30 |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- ... |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- 134047000000 |
- NaN |
-
-
- 1 |
- 1 |
- 2018-09-29 |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- ... |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- NaN |
- 107147000000 |
- NaN |
-
-
-
-
2 rows × 30 columns
+
+
+
+
+ |
+ Unnamed: 0 |
+ index |
+ CashAndCashEquivalentsAtCarryingValue |
+ MarketableSecuritiesCurrent |
+ AccountsReceivableNetCurrent |
+ InventoryNet |
+ NontradeReceivablesCurrent |
+ OtherAssetsCurrent |
+ AssetsCurrent |
+ MarketableSecuritiesNoncurrent |
+ ... |
+ LongTermDebtNoncurrent |
+ OtherLiabilitiesNoncurrent |
+ LiabilitiesNoncurrent |
+ Liabilities |
+ CommitmentsAndContingencies |
+ CommonStocksIncludingAdditionalPaidInCapital |
+ RetainedEarningsAccumulatedDeficit |
+ AccumulatedOtherComprehensiveIncomeLossNetOfTax |
+ StockholdersEquity |
+ LiabilitiesAndStockholdersEquity |
+
+
+
+
+ 0 |
+ 0 |
+ 2017-09-30 |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ ... |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ 134047000000 |
+ NaN |
+
+
+ 1 |
+ 1 |
+ 2018-09-29 |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ ... |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ NaN |
+ 107147000000 |
+ NaN |
+
+
+
+
2 rows × 30 columns
-# Define Python Tool [#define_python_tool]
-Here we define the python tool using langchain's PythonREPL. We also define `functions_map` that will later be used by the Cohere Agent to correctly map function name to the actual function. Lastly, we define the tools that will be passed in the Cohere API.
-```python PYTHON
+
+
+# Define Python Tool
+
+Here we define the python tool using langchain's PythonREPL. We also define `functions_map` that will later be used by the Cohere Agent to correctly map function name to the actual function. Lastly, we define the tools that will be passed in the Cohere API.
+
+
+
+```python
python_repl = PythonREPL()
python_tool = Tool(
name="python_repl",
@@ -295,11 +358,14 @@ tools = [
},]
```
-# Create Cohere Agent [#create_cohere_agent]
+
+
+# Create Cohere Agent
+
+As [Vanilla_Multi_Step_Tool_Use.ipynb](https://github.com/cohere-ai/cohere-developer-experience/blob/fbf6c8dad47d7557314e9248a267175c7a6908d8/notebooks/Vanilla_Multi_Step_Tool_Use.ipynb) shows, you have a lot of flexiblity on how you can customize and interact with the cohere agent. Here I am creating a wrapper so that it automatically determines when to stop calling the tools and output final answer. It will run maximum of 15 steps.
-As [Multi-Step Tool Use](https://docs.cohere.com/page/basic-multi-step) shows, you have a lot of flexiblity on how you can customize and interact with the cohere agent. Here I am creating a wrapper so that it automatically determines when to stop calling the tools and output final answer. It will run maximum of 15 steps.
-```python PYTHON
+```python
def cohere_agent(
message: str,
preamble: str,
@@ -373,30 +439,32 @@ def cohere_agent(
output = cohere_agent("can you use python to answer 1 + 1", None, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will use Python to answer this question.
+
+ running 0th step.
+ I will use Python to answer this question.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'print(1 + 1)'}
+ == tool results: [{'python_answer': '2\n'}]
+ The answer is **2**.
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'print(1 + 1)'}
-== tool results: [{'python_answer': '2\n'}]
-The answer is **2**.
-```
-# QnA over Single Table [#qna_over_single_table]
+
+
+# QnA over Single Table
-In the example below, we show how the Python tool can be used to load a dataframe and extract information from it. To do this successfully we need to:
+In the example below, we show how the python tool can be used to load a dataframe and extract information from it. To do this successfully we need to:
-- Pass the file name to the preamble so the model knows how to load the dataframe
-- Pass a preview of the dataframe in the preamble so the model knows which columns/rows to query
+1) pass the file name to the preamble so the model knows how to load the dataframe
+2) pass a preview of the dataframe in the preamble so the model knows which columns/rows to query
-We will ask the following questions given income statement data.
+We will ask the following questions given income statement data.
+1. what is the highest value of cost of goods and service?
+2. what is the largest gross profit margin?
+3. what is the minimum ratio of operating income loss divided by non operating income expense?
-- What is the highest value of cost of goods and service?
-- What is the largest gross profit margin?
-- What is the minimum ratio of operating income loss divided by non operating income expense?
-```python PYTHON
+```python
question_dict ={
'q1': ['what is the highest value of cost of goods and service?',169559000000],
'q2': ['what is the largest gross profit margin?',0.3836194330595236],
@@ -404,7 +472,8 @@ question_dict ={
}
```
-```python PYTHON
+
+```python
preamble = """
You are an expert who answers the user's question. You are working with a pandas dataframe in Python. The name of the dataframe is `income_statement.csv`.
Here is a preview of the dataframe:
@@ -414,6 +483,7 @@ Here is a preview of the dataframe:
print(preamble)
```
+
You are an expert who answers the user's question. You are working with a pandas dataframe in Python. The name of the dataframe is `income_statement.csv`.
Here is a preview of the dataframe:
| | Unnamed: 0 | index | RevenueFromContractWithCustomerExcludingAssessedTax | CostOfGoodsAndServicesSold | GrossProfit | ResearchAndDevelopmentExpense | SellingGeneralAndAdministrativeExpense | OperatingExpenses | OperatingIncomeLoss | NonoperatingIncomeExpense | IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest | IncomeTaxExpenseBenefit | NetIncomeLoss | EarningsPerShareBasic | EarningsPerShareDiluted | WeightedAverageNumberOfSharesOutstandingBasic | WeightedAverageNumberOfDilutedSharesOutstanding |
@@ -421,8 +491,11 @@ print(preamble)
| 0 | 0 | 2017-10-01-2018-09-29 | 265595000000 | 1.63756e+11 | 101839000000 | 1.4236e+10 | 1.6705e+10 | 3.0941e+10 | 7.0898e+10 | 2.005e+09 | 7.2903e+10 | 1.3372e+10 | 59531000000 | 3 | 2.98 | 1.98215e+10 | 2.00004e+10 |
| 1 | 1 | 2018-09-30-2018-12-29 | 84310000000 | nan | 32031000000 | nan | nan | nan | nan | nan | nan | nan | 19965000000 | 1.05 | 1.05 | nan | nan |
| 2 | 2 | 2018-09-30-2019-09-28 | 260174000000 | 1.61782e+11 | 98392000000 | 1.6217e+10 | 1.8245e+10 | 3.4462e+10 | 6.393e+10 | 1.807e+09 | 6.5737e+10 | 1.0481e+10 | 55256000000 | 2.99 | 2.97 | 1.84713e+10 | 1.85957e+10 |
+
+
+
-```python PYTHON
+```python
for qsn,val in question_dict.items():
print(f'question:{qsn}')
question = val[0]
@@ -432,57 +505,62 @@ for qsn,val in question_dict.items():
print('-'*50)
```
-```txt title="Output"
-question:q1
-
-running 0th step.
-I will use Python to find the highest value of 'CostOfGoodsAndServicesSold' in the 'income_statement.csv' dataframe.
-
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'CostOfGoodsAndServicesSold\'\nhighest_cost = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of \'CostOfGoodsAndServicesSold\' is {highest_cost}")'}
-== tool results: [{'python_answer': "The highest value of 'CostOfGoodsAndServicesSold' is 169559000000.0\n"}]
-The highest value of 'CostOfGoodsAndServicesSold' is 169559000000.0.
-GT Answer:169559000000
---------------------------------------------------
-question:q2
-
-running 0th step.
-I will write and execute Python code to find the largest gross profit margin.
-
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate gross profit margin\ndf[\'GrossProfitMargin\'] = df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\'] * 100\n\n# Find the largest gross profit margin\nlargest_gross_profit_margin = df[\'GrossProfitMargin\'].max()\n\nprint(f"The largest gross profit margin is {largest_gross_profit_margin:.2f}%")'}
-== tool results: [{'python_answer': 'The largest gross profit margin is 38.36%\n'}]
-The largest gross profit margin is 38.36%.
-GT Answer:0.3836194330595236
---------------------------------------------------
-question:q3
-
-running 0th step.
-I will use Python to find the minimum ratio of operating income loss divided by non-operating income expense.
-
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv("income_statement.csv")\n\n# Calculate the ratio of operating income loss to non-operating income expense\ndf["OperatingIncomeLossRatio"] = df["OperatingIncomeLoss"] / df["NonoperatingIncomeExpense"]\n\n# Find the minimum ratio\nmin_ratio = df["OperatingIncomeLossRatio"].min()\n\nprint(f"The minimum ratio of operating income loss to non-operating income expense is: {min_ratio:.2f}")'}
-== tool results: [{'python_answer': 'The minimum ratio of operating income loss to non-operating income expense is: 35.36\n'}]
-The minimum ratio of operating income loss to non-operating income expense is 35.36.
-GT Answer:35.360599
---------------------------------------------------
-```
+ question:q1
+
+ running 0th step.
+ I will use Python to find the highest value of 'CostOfGoodsAndServicesSold' in the 'income_statement.csv' dataframe.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'CostOfGoodsAndServicesSold\'\nhighest_cost = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of \'CostOfGoodsAndServicesSold\' is {highest_cost}")'}
+ == tool results: [{'python_answer': "The highest value of 'CostOfGoodsAndServicesSold' is 169559000000.0\n"}]
+ The highest value of 'CostOfGoodsAndServicesSold' is 169559000000.0.
+ GT Answer:169559000000
+ --------------------------------------------------
+ question:q2
+
+ running 0th step.
+ I will write and execute Python code to find the largest gross profit margin.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate gross profit margin\ndf[\'GrossProfitMargin\'] = df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\'] * 100\n\n# Find the largest gross profit margin\nlargest_gross_profit_margin = df[\'GrossProfitMargin\'].max()\n\nprint(f"The largest gross profit margin is {largest_gross_profit_margin:.2f}%")'}
+ == tool results: [{'python_answer': 'The largest gross profit margin is 38.36%\n'}]
+ The largest gross profit margin is 38.36%.
+ GT Answer:0.3836194330595236
+ --------------------------------------------------
+ question:q3
+
+ running 0th step.
+ I will use Python to find the minimum ratio of operating income loss divided by non-operating income expense.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv("income_statement.csv")\n\n# Calculate the ratio of operating income loss to non-operating income expense\ndf["OperatingIncomeLossRatio"] = df["OperatingIncomeLoss"] / df["NonoperatingIncomeExpense"]\n\n# Find the minimum ratio\nmin_ratio = df["OperatingIncomeLossRatio"].min()\n\nprint(f"The minimum ratio of operating income loss to non-operating income expense is: {min_ratio:.2f}")'}
+ == tool results: [{'python_answer': 'The minimum ratio of operating income loss to non-operating income expense is: 35.36\n'}]
+ The minimum ratio of operating income loss to non-operating income expense is 35.36.
+ GT Answer:35.360599
+ --------------------------------------------------
+
+
+
+
+# QnA over Multiple Tables
+
+We now make the task for the Agent more complicated, by asking it a question that answer can be computed only by retrieving relevant information from multiple tables:
-# QnA over Multiple Tables [#qna_over_multiple_tables]
+- Q: What is the ratio of the largest stockholders equity to the smallest revenue?
-We now make the task for the Agent more complicated by asking a question that can be only answered by retrieving relevant information from multiple tables:
+As you will see below, this question can be obtained only by accessing both the balance sheet and the income statement.
-- Q: What is the ratio of the largest stockholders equity to the smallest revenue?
-As you will see below, this question can be obtained only by accessing both the balance sheet and the income statement.
-```python PYTHON
+
+```python
question_dict ={
'q1': ['what is the ratio of the largest stockholders equity to the smallest revenue'],
}
```
-```python PYTHON
+
+```python
# get the largest stockholders equity
x = balance_sheet['StockholdersEquity'].astype(float).max()
print(f"The largest stockholders equity value is: {x}")
@@ -496,13 +574,13 @@ ratio = x/y
print(f"Their ratio is: {ratio}")
```
-```txt title="Output"
-The largest stockholders equity value is: 134047000000.0
-The smallest revenue value is: 53809000000.0
-Their ratio is: 2.4911631883142227
-```
+ The largest stockholders equity value is: 134047000000.0
+ The smallest revenue value is: 53809000000.0
+ Their ratio is: 2.4911631883142227
+
-```python PYTHON
+
+```python
preamble = """
You are an expert who answers the user's question in complete sentences. You are working with two pandas dataframe in Python. Ensure your output is a string.
@@ -517,53 +595,58 @@ Here is a preview of the `balance_sheet.csv` dataframe:
print(preamble)
```
-```txt title="Output"
-You are an expert who answers the user's question in complete sentences. You are working with two pandas dataframe in Python. Ensure your output is a string.
+
+ You are an expert who answers the user's question in complete sentences. You are working with two pandas dataframe in Python. Ensure your output is a string.
+
+ Here is a preview of the `income_statement.csv` dataframe:
+ | | Unnamed: 0 | index | RevenueFromContractWithCustomerExcludingAssessedTax | CostOfGoodsAndServicesSold | GrossProfit | ResearchAndDevelopmentExpense | SellingGeneralAndAdministrativeExpense | OperatingExpenses | OperatingIncomeLoss | NonoperatingIncomeExpense | IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest | IncomeTaxExpenseBenefit | NetIncomeLoss | EarningsPerShareBasic | EarningsPerShareDiluted | WeightedAverageNumberOfSharesOutstandingBasic | WeightedAverageNumberOfDilutedSharesOutstanding |
+ |---:|-------------:|:----------------------|------------------------------------------------------:|-----------------------------:|--------------:|--------------------------------:|-----------------------------------------:|--------------------:|----------------------:|----------------------------:|----------------------------------------------------------------------------------------------:|--------------------------:|----------------:|------------------------:|--------------------------:|------------------------------------------------:|--------------------------------------------------:|
+ | 0 | 0 | 2017-10-01-2018-09-29 | 265595000000 | 1.63756e+11 | 101839000000 | 1.4236e+10 | 1.6705e+10 | 3.0941e+10 | 7.0898e+10 | 2.005e+09 | 7.2903e+10 | 1.3372e+10 | 59531000000 | 3 | 2.98 | 1.98215e+10 | 2.00004e+10 |
+ | 1 | 1 | 2018-09-30-2018-12-29 | 84310000000 | nan | 32031000000 | nan | nan | nan | nan | nan | nan | nan | 19965000000 | 1.05 | 1.05 | nan | nan |
+ | 2 | 2 | 2018-09-30-2019-09-28 | 260174000000 | 1.61782e+11 | 98392000000 | 1.6217e+10 | 1.8245e+10 | 3.4462e+10 | 6.393e+10 | 1.807e+09 | 6.5737e+10 | 1.0481e+10 | 55256000000 | 2.99 | 2.97 | 1.84713e+10 | 1.85957e+10 |
+
+ Here is a preview of the `balance_sheet.csv` dataframe:
+ | | Unnamed: 0 | index | CashAndCashEquivalentsAtCarryingValue | MarketableSecuritiesCurrent | AccountsReceivableNetCurrent | InventoryNet | NontradeReceivablesCurrent | OtherAssetsCurrent | AssetsCurrent | MarketableSecuritiesNoncurrent | PropertyPlantAndEquipmentNet | OtherAssetsNoncurrent | AssetsNoncurrent | Assets | AccountsPayableCurrent | OtherLiabilitiesCurrent | ContractWithCustomerLiabilityCurrent | CommercialPaper | LongTermDebtCurrent | LiabilitiesCurrent | LongTermDebtNoncurrent | OtherLiabilitiesNoncurrent | LiabilitiesNoncurrent | Liabilities | CommitmentsAndContingencies | CommonStocksIncludingAdditionalPaidInCapital | RetainedEarningsAccumulatedDeficit | AccumulatedOtherComprehensiveIncomeLossNetOfTax | StockholdersEquity | LiabilitiesAndStockholdersEquity |
+ |---:|-------------:|:-----------|----------------------------------------:|------------------------------:|-------------------------------:|---------------:|-----------------------------:|---------------------:|----------------:|---------------------------------:|-------------------------------:|------------------------:|-------------------:|--------------:|-------------------------:|--------------------------:|---------------------------------------:|------------------:|----------------------:|---------------------:|-------------------------:|-----------------------------:|------------------------:|--------------:|------------------------------:|-----------------------------------------------:|-------------------------------------:|--------------------------------------------------:|---------------------:|-----------------------------------:|
+ | 0 | 0 | 2017-09-30 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 134047000000 | nan |
+ | 1 | 1 | 2018-09-29 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 107147000000 | nan |
+ | 2 | 2 | 2019-09-28 | 4.8844e+10 | 5.1713e+10 | 2.2926e+10 | 4.106e+09 | 2.2878e+10 | 1.2352e+10 | 1.62819e+11 | 1.05341e+11 | 3.7378e+10 | 3.2978e+10 | 1.75697e+11 | 3.38516e+11 | 4.6236e+10 | 3.772e+10 | 5.522e+09 | 5.98e+09 | 1.026e+10 | 1.05718e+11 | 9.1807e+10 | 5.0503e+10 | 1.4231e+11 | 2.48028e+11 | 0 | 4.5174e+10 | 4.5898e+10 | -5.84e+08 | 90488000000 | 3.38516e+11 |
+
-Here is a preview of the `income_statement.csv` dataframe:
-| | Unnamed: 0 | index | RevenueFromContractWithCustomerExcludingAssessedTax | CostOfGoodsAndServicesSold | GrossProfit | ResearchAndDevelopmentExpense | SellingGeneralAndAdministrativeExpense | OperatingExpenses | OperatingIncomeLoss | NonoperatingIncomeExpense | IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest | IncomeTaxExpenseBenefit | NetIncomeLoss | EarningsPerShareBasic | EarningsPerShareDiluted | WeightedAverageNumberOfSharesOutstandingBasic | WeightedAverageNumberOfDilutedSharesOutstanding |
-|---:|-------------:|:----------------------|------------------------------------------------------:|-----------------------------:|--------------:|--------------------------------:|-----------------------------------------:|--------------------:|----------------------:|----------------------------:|----------------------------------------------------------------------------------------------:|--------------------------:|----------------:|------------------------:|--------------------------:|------------------------------------------------:|--------------------------------------------------:|
-| 0 | 0 | 2017-10-01-2018-09-29 | 265595000000 | 1.63756e+11 | 101839000000 | 1.4236e+10 | 1.6705e+10 | 3.0941e+10 | 7.0898e+10 | 2.005e+09 | 7.2903e+10 | 1.3372e+10 | 59531000000 | 3 | 2.98 | 1.98215e+10 | 2.00004e+10 |
-| 1 | 1 | 2018-09-30-2018-12-29 | 84310000000 | nan | 32031000000 | nan | nan | nan | nan | nan | nan | nan | 19965000000 | 1.05 | 1.05 | nan | nan |
-| 2 | 2 | 2018-09-30-2019-09-28 | 260174000000 | 1.61782e+11 | 98392000000 | 1.6217e+10 | 1.8245e+10 | 3.4462e+10 | 6.393e+10 | 1.807e+09 | 6.5737e+10 | 1.0481e+10 | 55256000000 | 2.99 | 2.97 | 1.84713e+10 | 1.85957e+10 |
-Here is a preview of the `balance_sheet.csv` dataframe:
-| | Unnamed: 0 | index | CashAndCashEquivalentsAtCarryingValue | MarketableSecuritiesCurrent | AccountsReceivableNetCurrent | InventoryNet | NontradeReceivablesCurrent | OtherAssetsCurrent | AssetsCurrent | MarketableSecuritiesNoncurrent | PropertyPlantAndEquipmentNet | OtherAssetsNoncurrent | AssetsNoncurrent | Assets | AccountsPayableCurrent | OtherLiabilitiesCurrent | ContractWithCustomerLiabilityCurrent | CommercialPaper | LongTermDebtCurrent | LiabilitiesCurrent | LongTermDebtNoncurrent | OtherLiabilitiesNoncurrent | LiabilitiesNoncurrent | Liabilities | CommitmentsAndContingencies | CommonStocksIncludingAdditionalPaidInCapital | RetainedEarningsAccumulatedDeficit | AccumulatedOtherComprehensiveIncomeLossNetOfTax | StockholdersEquity | LiabilitiesAndStockholdersEquity |
-|---:|-------------:|:-----------|----------------------------------------:|------------------------------:|-------------------------------:|---------------:|-----------------------------:|---------------------:|----------------:|---------------------------------:|-------------------------------:|------------------------:|-------------------:|--------------:|-------------------------:|--------------------------:|---------------------------------------:|------------------:|----------------------:|---------------------:|-------------------------:|-----------------------------:|------------------------:|--------------:|------------------------------:|-----------------------------------------------:|-------------------------------------:|--------------------------------------------------:|---------------------:|-----------------------------------:|
-| 0 | 0 | 2017-09-30 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 134047000000 | nan |
-| 1 | 1 | 2018-09-29 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 107147000000 | nan |
-| 2 | 2 | 2019-09-28 | 4.8844e+10 | 5.1713e+10 | 2.2926e+10 | 4.106e+09 | 2.2878e+10 | 1.2352e+10 | 1.62819e+11 | 1.05341e+11 | 3.7378e+10 | 3.2978e+10 | 1.75697e+11 | 3.38516e+11 | 4.6236e+10 | 3.772e+10 | 5.522e+09 | 5.98e+09 | 1.026e+10 | 1.05718e+11 | 9.1807e+10 | 5.0503e+10 | 1.4231e+11 | 2.48028e+11 | 0 | 4.5174e+10 | 4.5898e+10 | -5.84e+08 | 90488000000 | 3.38516e+11 |
-```
-```python PYTHON
+```python
for qsn,val in question_dict.items():
print(f'question:{qsn}')
question = val[0]
output = cohere_agent(question, preamble, tools, verbose=True)
```
-```txt title="Output"
-question:q1
+ question:q1
+
+ running 0th step.
+ I will use the provided code to find the ratio of the largest stockholders equity to the smallest revenue.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\n# Read the CSV files into dataframes\nincome_statement = pd.read_csv(\'income_statement.csv\')\nbalance_sheet = pd.read_csv(\'balance_sheet.csv\')\n\n# Find the smallest revenue\nsmallest_revenue = income_statement[\'RevenueFromContractWithCustomerExcludingAssessedTax\'].min()\n\n# Find the largest stockholders equity\nlargest_stockholders_equity = balance_sheet[\'StockholdersEquity\'].max()\n\n# Calculate the ratio\nratio = largest_stockholders_equity / smallest_revenue\nprint(f"The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}")'}
+ == tool results: [{'python_answer': 'The ratio of the largest stockholders equity to the smallest revenue is 2.49\n'}]
+ The ratio of the largest stockholders equity to the smallest revenue is 2.49.
-running 0th step.
-I will use the provided code to find the ratio of the largest stockholders equity to the smallest revenue.
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\n# Read the CSV files into dataframes\nincome_statement = pd.read_csv(\'income_statement.csv\')\nbalance_sheet = pd.read_csv(\'balance_sheet.csv\')\n\n# Find the smallest revenue\nsmallest_revenue = income_statement[\'RevenueFromContractWithCustomerExcludingAssessedTax\'].min()\n\n# Find the largest stockholders equity\nlargest_stockholders_equity = balance_sheet[\'StockholdersEquity\'].max()\n\n# Calculate the ratio\nratio = largest_stockholders_equity / smallest_revenue\nprint(f"The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}")'}
-== tool results: [{'python_answer': 'The ratio of the largest stockholders equity to the smallest revenue is 2.49\n'}]
-The ratio of the largest stockholders equity to the smallest revenue is 2.49.
-```
+
+
+# Error Resilience
-# Error Resilience [#error_resilience]
+In the previous example over single table, the model successfully answered your questions. However, the model may not always have access to the preview of the data. You will see that when we remove the preview from the preamble, the model is run into an error and not produce the answer. We will solve this problem with two different ways:
-In the previous example over single table, the model successfully answered your questions. However, the model may not always have access to the preview of the data. You will see that when we remove the preview from the preamble, the model runs into an error and is not produce the answer. We will solve this problem with two different ways:
+1. Asking the model to keep trying until it fixes the issue.
+2. Giving the model another tool to view the data and telling it to preview the data before writing code.
-- Asking the model to keep trying until it fixes the issue.
-- Giving the model another tool to view the data and telling it to preview the data before writing code.
+You will see that the second method is able to come to the answer with fewer steps.
-You will see that the second method is able to come to the answer with fewer steps.
-```python PYTHON
+
+```python
preamble = """
You are an expert who answers the user's question. You are working with a pandas dataframe in Python. The name of the dataframe is `income_statement.csv`.
"""
@@ -573,19 +656,20 @@ question1 = "what is the highest value of cost of goods and service?"
output = cohere_agent(question1, preamble, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will use Python to find the highest value of 'Cost of Goods and Service' in the 'income_statement.csv' file.
+
+ running 0th step.
+ I will use Python to find the highest value of 'Cost of Goods and Service' in the 'income_statement.csv' file.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Service\'\nhighest_cost = df[\'Cost of Goods and Service\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Service\' is: {highest_cost}")'}
+ == tool results: [{'python_answer': "KeyError('Cost of Goods and Service')"}]
+ Sorry, there is no column named 'Cost of Goods and Service' in the 'income_statement.csv' file.
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Service\'\nhighest_cost = df[\'Cost of Goods and Service\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Service\' is: {highest_cost}")'}
-== tool results: [{'python_answer': "KeyError('Cost of Goods and Service')"}]
-Sorry, there is no column named 'Cost of Goods and Service' in the 'income_statement.csv' file.
-```
-As you see above, the model failed to execute because it assumed certain column names but they turned out to be wrong. One simple fix is to tell the model to continue to solve the problem in the face of error.
+As you see above, the model failed to execute because it assumed certain column names but they turned out to be wrong. One simple fix is to tell the model to continue to solve the problem in the face of error.
+
-```python PYTHON
+```python
preamble = """
You are an expert who answers the user's question. You are working with a pandas dataframe in Python. The name of the dataframe is `income_statement.csv`.
If you run into error, keep trying until you fix it. You may need to view the data to understand the error.
@@ -596,31 +680,34 @@ question1 = "what is the highest value of cost of goods and service?"
output = cohere_agent(question1, preamble, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will use Python to find the highest value of cost of goods and service.
+
+ running 0th step.
+ I will use Python to find the highest value of cost of goods and service.
+
+ running 1th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Services\'\nhighest_cost = df[\'Cost of Goods and Services\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Services\' is: {highest_cost}")'}
+ == tool results: [{'python_answer': "KeyError('Cost of Goods and Services')"}]
+ I encountered an error. I will now view the data to understand the error.
+
+ running 2th step.
+ = running tool run_python_code, with parameters: {'code': "import pandas as pd\n\ndf = pd.read_csv('income_statement.csv')\n\nprint(df.columns)"}
+ == tool results: [{'python_answer': "Index(['Unnamed: 0', 'index',\n 'RevenueFromContractWithCustomerExcludingAssessedTax',\n 'CostOfGoodsAndServicesSold', 'GrossProfit',\n 'ResearchAndDevelopmentExpense',\n 'SellingGeneralAndAdministrativeExpense', 'OperatingExpenses',\n 'OperatingIncomeLoss', 'NonoperatingIncomeExpense',\n 'IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest',\n 'IncomeTaxExpenseBenefit', 'NetIncomeLoss', 'EarningsPerShareBasic',\n 'EarningsPerShareDiluted',\n 'WeightedAverageNumberOfSharesOutstandingBasic',\n 'WeightedAverageNumberOfDilutedSharesOutstanding'],\n dtype='object')\n"}]
+ I found that the column name is 'CostOfGoodsAndServicesSold'. I will now use this to find the highest value.
+
+ running 3th step.
+ = running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Services\'\nhighest_cost = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Services\' is: {highest_cost}")'}
+ == tool results: [{'python_answer': "The highest value of 'Cost of Goods and Services' is: 169559000000.0\n"}]
+ The highest value of 'Cost of Goods and Services' is 169559000000.0.
-running 1th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Services\'\nhighest_cost = df[\'Cost of Goods and Services\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Services\' is: {highest_cost}")'}
-== tool results: [{'python_answer': "KeyError('Cost of Goods and Services')"}]
-I encountered an error. I will now view the data to understand the error.
-running 2th step.
-= running tool run_python_code, with parameters: {'code': "import pandas as pd\n\ndf = pd.read_csv('income_statement.csv')\n\nprint(df.columns)"}
-== tool results: [{'python_answer': "Index(['Unnamed: 0', 'index',\n 'RevenueFromContractWithCustomerExcludingAssessedTax',\n 'CostOfGoodsAndServicesSold', 'GrossProfit',\n 'ResearchAndDevelopmentExpense',\n 'SellingGeneralAndAdministrativeExpense', 'OperatingExpenses',\n 'OperatingIncomeLoss', 'NonoperatingIncomeExpense',\n 'IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest',\n 'IncomeTaxExpenseBenefit', 'NetIncomeLoss', 'EarningsPerShareBasic',\n 'EarningsPerShareDiluted',\n 'WeightedAverageNumberOfSharesOutstandingBasic',\n 'WeightedAverageNumberOfDilutedSharesOutstanding'],\n dtype='object')\n"}]
-I found that the column name is 'CostOfGoodsAndServicesSold'. I will now use this to find the highest value.
+
-running 3th step.
-= running tool run_python_code, with parameters: {'code': 'import pandas as pd\n\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value of \'Cost of Goods and Services\'\nhighest_cost = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of \'Cost of Goods and Services\' is: {highest_cost}")'}
-== tool results: [{'python_answer': "The highest value of 'Cost of Goods and Services' is: 169559000000.0\n"}]
-The highest value of 'Cost of Goods and Services' is 169559000000.0.
-```
+### Add Viewing Tool
-### Add Viewing Tool [#add_viewing_tool]
+What if we directly give the model the ability to view the data as a tool so that it can explicitly use it instead of indirectly figuring it out?
-What if we directly give the model the ability to view the data as a tool so that it can explicitly use it instead of indirectly figuring it out?
-```python PYTHON
+```python
def view_csv_data(path: str) -> dict:
"""
Function to view the head, tail and shape of a given csv file.
@@ -664,7 +751,8 @@ tools = [
]
```
-```python PYTHON
+
+```python
preamble = """
You are an expert who answers the user's question. You are working with a pandas dataframe in Python. The name of the dataframe is `income_statement.csv`.
Always view the data first to write flawless code.
@@ -675,19 +763,19 @@ question1 = "what is the highest value of cost of goods and service?"
output = cohere_agent(question1, preamble, tools, verbose=True)
```
-```txt title="Output"
-running 0th step.
-I will first view the data and then write and execute Python code to find the highest value of cost of goods and service.
-
-running 1th step.
-= running tool view_csv_data, with parameters: {'path': 'income_statement.csv'}
-== tool results: [{'head': ' Unnamed: 0 index RevenueFromContractWithCustomerExcludingAssessedTax CostOfGoodsAndServicesSold GrossProfit ResearchAndDevelopmentExpense SellingGeneralAndAdministrativeExpense OperatingExpenses OperatingIncomeLoss NonoperatingIncomeExpense IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest IncomeTaxExpenseBenefit NetIncomeLoss EarningsPerShareBasic EarningsPerShareDiluted WeightedAverageNumberOfSharesOutstandingBasic WeightedAverageNumberOfDilutedSharesOutstanding\n0 0 2017-10-01-2018-09-29 265595000000 1.637560e+11 101839000000 1.423600e+10 1.670500e+10 3.094100e+10 7.089800e+10 2.005000e+09 7.290300e+10 1.337200e+10 59531000000 3.00 2.98 1.982151e+10 2.000044e+10\n1 1 2018-09-30-2018-12-29 84310000000 NaN 32031000000 NaN NaN NaN NaN NaN NaN NaN 19965000000 1.05 1.05 NaN NaN\n2 2 2018-09-30-2019-09-28 260174000000 1.617820e+11 98392000000 1.621700e+10 1.824500e+10 3.446200e+10 6.393000e+10 1.807000e+09 6.573700e+10 1.048100e+10 55256000000 2.99 2.97 1.847134e+10 1.859565e+10\n3 3 2018-12-30-2019-03-30 58015000000 NaN 21821000000 NaN NaN NaN NaN NaN NaN NaN 11561000000 0.62 0.61 NaN NaN\n4 4 2019-03-31-2019-06-29 53809000000 NaN 20227000000 NaN NaN NaN NaN NaN NaN NaN 10044000000 0.55 0.55 NaN NaN', 'tail': ' Unnamed: 0 index RevenueFromContractWithCustomerExcludingAssessedTax CostOfGoodsAndServicesSold GrossProfit ResearchAndDevelopmentExpense SellingGeneralAndAdministrativeExpense OperatingExpenses OperatingIncomeLoss NonoperatingIncomeExpense IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest IncomeTaxExpenseBenefit NetIncomeLoss EarningsPerShareBasic EarningsPerShareDiluted WeightedAverageNumberOfSharesOutstandingBasic WeightedAverageNumberOfDilutedSharesOutstanding\n6 6 2019-09-29-2019-12-28 91819000000 NaN 35217000000 NaN NaN NaN NaN NaN NaN NaN 22236000000 1.26 1.25 NaN NaN\n7 7 2019-09-29-2020-09-26 274515000000 1.695590e+11 104956000000 1.875200e+10 1.991600e+10 3.866800e+10 6.628800e+10 803000000.0 6.709100e+10 9.680000e+09 57411000000 3.31 3.28 1.735212e+10 1.752821e+10\n8 8 2019-12-29-2020-03-28 58313000000 NaN 22370000000 NaN NaN NaN NaN NaN NaN NaN 11249000000 0.64 0.64 NaN NaN\n9 9 2020-03-29-2020-06-27 59685000000 NaN 22680000000 NaN NaN NaN NaN NaN NaN NaN 11253000000 0.65 0.65 NaN NaN\n10 10 2020-06-28-2020-09-26 64698000000 NaN 24689000000 NaN NaN NaN NaN NaN NaN NaN 12673000000 0.74 0.73 NaN NaN', 'shape': '(11, 17)'}]
-The column name is 'CostOfGoodsAndServicesSold'. I will now write and execute Python code to find the highest value in this column.
-
-running 2th step.
-= running tool run_python_code, with parameters: {'code': "import pandas as pd\n\ndf = pd.read_csv('income_statement.csv')\n\nprint(df['CostOfGoodsAndServicesSold'].max())"}
-== tool results: [{'python_answer': '169559000000.0\n'}]
-The highest value of cost of goods and services is 169559000000.0.
-```
-
-By being prescriptive, we were able to cut down a step and get to the answer faster.
+
+ running 0th step.
+ I will first view the data and then write and execute Python code to find the highest value of cost of goods and service.
+
+ running 1th step.
+ = running tool view_csv_data, with parameters: {'path': 'income_statement.csv'}
+ == tool results: [{'head': ' Unnamed: 0 index RevenueFromContractWithCustomerExcludingAssessedTax CostOfGoodsAndServicesSold GrossProfit ResearchAndDevelopmentExpense SellingGeneralAndAdministrativeExpense OperatingExpenses OperatingIncomeLoss NonoperatingIncomeExpense IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest IncomeTaxExpenseBenefit NetIncomeLoss EarningsPerShareBasic EarningsPerShareDiluted WeightedAverageNumberOfSharesOutstandingBasic WeightedAverageNumberOfDilutedSharesOutstanding\n0 0 2017-10-01-2018-09-29 265595000000 1.637560e+11 101839000000 1.423600e+10 1.670500e+10 3.094100e+10 7.089800e+10 2.005000e+09 7.290300e+10 1.337200e+10 59531000000 3.00 2.98 1.982151e+10 2.000044e+10\n1 1 2018-09-30-2018-12-29 84310000000 NaN 32031000000 NaN NaN NaN NaN NaN NaN NaN 19965000000 1.05 1.05 NaN NaN\n2 2 2018-09-30-2019-09-28 260174000000 1.617820e+11 98392000000 1.621700e+10 1.824500e+10 3.446200e+10 6.393000e+10 1.807000e+09 6.573700e+10 1.048100e+10 55256000000 2.99 2.97 1.847134e+10 1.859565e+10\n3 3 2018-12-30-2019-03-30 58015000000 NaN 21821000000 NaN NaN NaN NaN NaN NaN NaN 11561000000 0.62 0.61 NaN NaN\n4 4 2019-03-31-2019-06-29 53809000000 NaN 20227000000 NaN NaN NaN NaN NaN NaN NaN 10044000000 0.55 0.55 NaN NaN', 'tail': ' Unnamed: 0 index RevenueFromContractWithCustomerExcludingAssessedTax CostOfGoodsAndServicesSold GrossProfit ResearchAndDevelopmentExpense SellingGeneralAndAdministrativeExpense OperatingExpenses OperatingIncomeLoss NonoperatingIncomeExpense IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest IncomeTaxExpenseBenefit NetIncomeLoss EarningsPerShareBasic EarningsPerShareDiluted WeightedAverageNumberOfSharesOutstandingBasic WeightedAverageNumberOfDilutedSharesOutstanding\n6 6 2019-09-29-2019-12-28 91819000000 NaN 35217000000 NaN NaN NaN NaN NaN NaN NaN 22236000000 1.26 1.25 NaN NaN\n7 7 2019-09-29-2020-09-26 274515000000 1.695590e+11 104956000000 1.875200e+10 1.991600e+10 3.866800e+10 6.628800e+10 803000000.0 6.709100e+10 9.680000e+09 57411000000 3.31 3.28 1.735212e+10 1.752821e+10\n8 8 2019-12-29-2020-03-28 58313000000 NaN 22370000000 NaN NaN NaN NaN NaN NaN NaN 11249000000 0.64 0.64 NaN NaN\n9 9 2020-03-29-2020-06-27 59685000000 NaN 22680000000 NaN NaN NaN NaN NaN NaN NaN 11253000000 0.65 0.65 NaN NaN\n10 10 2020-06-28-2020-09-26 64698000000 NaN 24689000000 NaN NaN NaN NaN NaN NaN NaN 12673000000 0.74 0.73 NaN NaN', 'shape': '(11, 17)'}]
+ The column name is 'CostOfGoodsAndServicesSold'. I will now write and execute Python code to find the highest value in this column.
+
+ running 2th step.
+ = running tool run_python_code, with parameters: {'code': "import pandas as pd\n\ndf = pd.read_csv('income_statement.csv')\n\nprint(df['CostOfGoodsAndServicesSold'].max())"}
+ == tool results: [{'python_answer': '169559000000.0\n'}]
+ The highest value of cost of goods and services is 169559000000.0.
+
+
+By being prescriptive, we were able to cut down a step and get to the answer faster.
diff --git a/fern/pages/cookbooks/csv-agent.mdx b/fern/pages/cookbooks/csv-agent.mdx
index d21bc7182..b89c82611 100644
--- a/fern/pages/cookbooks/csv-agent.mdx
+++ b/fern/pages/cookbooks/csv-agent.mdx
@@ -3,7 +3,7 @@ title: Financial CSV Agent with Langchain
slug: /page/csv-agent
description: "This page describes how to use Cohere's models to build an agent able to work with CSV data."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG, AI agents, CSV"
---
@@ -14,21 +14,21 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Shaan Desai",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg"
+ }
]}
/>
-
-# Notebook Overview
+
+
+
-## Motivation
+## Motivation
Tabular data reasoning continues to be an exciting application of Agents, particularly in the financial domain, where multiple reasoning steps may be needed to identify the right answer. For example, a financial analyst working with financial statements may be interested in computing various financial ratios with natural language queries.
Some examples may include:
-
- ROE (Return on Equity) = Net Income / Shareholder's Equity
- Net Profit Margin = Net Income / Revenue
- Asset Turnover = Revenue / Average Total Assets
@@ -37,12 +37,22 @@ Some examples may include:
Having an Agent which is able to correctly compute these and other ratios would be a great help for any analyst in the field of Finance.
## Objective
+In this notebook we explore how to setup a [Cohere ReAct Agent](https://github.com/langchain-ai/langchain-cohere/blob/main/libs/cohere/langchain_cohere/cohere_agent.py) to answer questions over tables in Apple's SEC10K 2020 form. We show how this can be done with two variants of a langchain python tool, one that requires you to pass the full path of the dataframe and another that requires the dataframe objects to be loaded in memory. While there is no major difference between the two approaches, we present both to show how to manage files that are loaded in memory vs files in storage.
-In this notebook we explore how to setup a [Cohere ReAct Agent](https://github.com/langchain-ai/langchain-cohere/blob/main/libs/cohere/langchain_cohere/cohere_agent.py) to answer questions over tables in Apple's SEC10K 2020 form. We show how this can be done with two variants of a Langchain Python tool, one that requires you to pass the full path of the dataframe and another that requires the dataframe objects to be loaded in memory. While there is no major difference between the two approaches, we present both to show how to manage files that are loaded in memory vs files in storage.
+## Table of Contents
-# Setup [#sec_step0]
+- [Setup](#sec_step0)
+- [Introduction](#sec_step1)
+- [QnA over Single Table](#sec_step2)
+ - [Agent with Python Tool](#sec_step2_sub1)
+ - [Agent with Python Tool that takes tables as input](#sec_step2_sub2)
+- [QnA over Multiple Tables](#sec_step3)
-```python PYTHON
+
+# Setup
+
+
+```python
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain.agents import AgentExecutor
from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
@@ -54,38 +64,49 @@ from langchain_experimental.utilities import PythonREPL
from langchain_experimental.tools.python.tool import PythonAstREPLTool
```
-```python PYTHON
+
+```python
+####################################################################################################
+#
# Uncomment if you need to install the following packages
+#
+####################################################################################################
+
#!pip install --quiet langchain langchain_cohere langchain_experimental --upgrade
#!pip install sec-api
```
-# Introduction [#sec_step1]
+
+# Introduction
The aim of this notebook is to showcase how Cohere Langchain Agents can be used to answer questions over tabular data.
-This notebook assumes the input is a set of csv files extracted from Apple's SEC 10K filings.
+This notebook assumes the input is a set of csv files extracted from Apples SEC 10K filings.
### Data Loading
-We use the sec-api to download the income statement and balance sheet from the SEC 10K .htm file. Please note that the tables need to be parsed such that the index is numerical as the python code generation struggles to filter based on index. We have processed the tables and provided them for you. They can be found [here](https://github.com/cohere-ai/cohere-developer-experience/tree/main/notebooks/agents/financial-csv-agent).
+We use the sec-api to download the income statement and balance sheet from the SEC 10K .htm file. Please note that the tables need to be parsed such that the index is numerical as the python code generation struggles to filter based on index. We have processed the tables and provided them for you.
-```python PYTHON
+
+```python
income_statement = pd.read_csv('income_statement.csv')
balance_sheet = pd.read_csv('balance_sheet.csv')
```
-# QnA over Single Table{" "} [#sec_step2]
+
+# QnA over Single Table
-## Agent with Python Tool [#sec_step2_sub1]
+
+## Agent with Python Tool
In the example below, we show how the python tool can be used to load a dataframe and extract information from it. To do this successfully we need to:
-- Pass the file name to the preamble so the model knows how to load the dataframe.
-- Pass a preview of the dataframe in the preamble so the model knows which columns/rows to query.
+1) pass the file name to the preamble so the model knows how to load the dataframe
+2) pass a preview of the dataframe in the preamble so the model knows which columns/rows to query
+
+First, let's implement the ReAct agent
-First, let's implement the ReAct agent.
-```python PYTHON
+```python
# instantiate the Cohere llm
llm = ChatCohere(model="command-r", temperature=0.1,cohere_api_key="",verbose=True)
@@ -101,7 +122,7 @@ python_tool.name = "python_interpreter"
class ToolInput(BaseModel):
code: str = Field(description="Python code to execute.")
python_tool.args_schema = ToolInput
-tools=[python_tool]
+tools=[python_tool]
# define the prompt template
prompt = ChatPromptTemplate.from_template("{input}")
@@ -128,7 +149,8 @@ Here is a preview of the dataframe:
Then, we define the dictionary including the questions we want the Agent to answer, and their answer.
-```python PYTHON
+
+```python
question_dict ={
'q1': ['what is the highest value of cost of goods and service?',169559000000],
'q2': ['what is the largest gross profit margin?',0.3836194330595236],
@@ -136,9 +158,10 @@ question_dict ={
}
```
-Let's now see how the Agent answers each of the questions.
+Let's now see how the Agent answers to each of the questions
+
-```python PYTHON
+```python
for qsn,val in question_dict.items():
print(f'question:{qsn}')
agent_executor.invoke({
@@ -149,64 +172,65 @@ for qsn,val in question_dict.items():
print('-'*50)
```
-```txt title="Output"
-question:q1
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to find the highest value of Cost of Goods and Services Sold from the provided dataframe.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value in the \'CostOfGoodsAndServicesSold\' column\nmax_value = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of Cost of Goods and Services Sold is {max_value}")'}}
-[0m[36;1m[1;3mThe highest value of Cost of Goods and Services Sold is 169559000000.0
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The highest value of Cost of Goods and Services Sold is 169559000000.0.
-Grounded answer: The highest value of Cost of Goods and Services Sold is 169559000000.0.[0m
-
-[1m> Finished chain.[0m
-GT Answer:169559000000
---------------------------------------------------
-question:q2
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to calculate the largest gross profit margin from the data frame provided.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the gross profit margin as a percentage\ndf[\'GrossProfitMargin\'] = (df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\']) * 100\n\n# Find the row with the maximum gross profit margin\nmax_margin_row = df.loc[df[\'GrossProfitMargin\'].idxmax()]\n\nprint(f"The largest gross profit margin is {max_margin_row[\'GrossProfitMargin\']}% on {max_margin_row[\'index\']}")\n'}}
-[0m[36;1m[1;3mThe largest gross profit margin is 38.36194330595236% on 2019-12-29-2020-03-28
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.
-Grounded answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.[0m
-
-[1m> Finished chain.[0m
-GT Answer:0.3836194330595236
---------------------------------------------------
-question:q3
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to calculate the minimum ratio of Operating Income Loss divided by Non Operating Income Expense.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the ratio\nratios = df[\'OperatingIncomeLoss\'] / df[\'NonoperatingIncomeExpense\']\n\nprint("Minimum ratio:", ratios.min())'}}
-[0m[36;1m[1;3mMinimum ratio: 35.36059850374065
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.
-Grounded answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.[0m
-
-[1m> Finished chain.[0m
-GT Answer:35.360599
---------------------------------------------------
-```
+ question:q1
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to find the highest value of Cost of Goods and Services Sold from the provided dataframe.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Find the highest value in the \'CostOfGoodsAndServicesSold\' column\nmax_value = df[\'CostOfGoodsAndServicesSold\'].max()\n\nprint(f"The highest value of Cost of Goods and Services Sold is {max_value}")'}}
+ [0m[36;1m[1;3mThe highest value of Cost of Goods and Services Sold is 169559000000.0
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The highest value of Cost of Goods and Services Sold is 169559000000.0.
+ Grounded answer: The highest value of Cost of Goods and Services Sold is 169559000000.0.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:169559000000
+ --------------------------------------------------
+ question:q2
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to calculate the largest gross profit margin from the data frame provided.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the gross profit margin as a percentage\ndf[\'GrossProfitMargin\'] = (df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\']) * 100\n\n# Find the row with the maximum gross profit margin\nmax_margin_row = df.loc[df[\'GrossProfitMargin\'].idxmax()]\n\nprint(f"The largest gross profit margin is {max_margin_row[\'GrossProfitMargin\']}% on {max_margin_row[\'index\']}")\n'}}
+ [0m[36;1m[1;3mThe largest gross profit margin is 38.36194330595236% on 2019-12-29-2020-03-28
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.
+ Grounded answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:0.3836194330595236
+ --------------------------------------------------
+ question:q3
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to calculate the minimum ratio of Operating Income Loss divided by Non Operating Income Expense.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the ratio\nratios = df[\'OperatingIncomeLoss\'] / df[\'NonoperatingIncomeExpense\']\n\nprint("Minimum ratio:", ratios.min())'}}
+ [0m[36;1m[1;3mMinimum ratio: 35.36059850374065
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.
+ Grounded answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:35.360599
+ --------------------------------------------------
+
Nice! The agent uses the Python tool to write the code to access the data in the tables, and perform the required calculations.
-## Agent with Python Tool that takes tables as input [#sec_step2_sub2]
+
+## Agent with Python Tool that takes tables as input
In the example above, the model needs to load the dataframe in the python call before carrying out operations. In this example, we show how to pass the dataframes to the python tool so it has the file already loaded.
-```python PYTHON
+
+```python
# call the PythonAstREPLTool in order to pass tables to the tool
df_locals = {'df':pd.read_csv('income_statement.csv')}
tools = [PythonAstREPLTool(locals=df_locals)]
@@ -230,9 +254,10 @@ Here is a preview of the dataframe:
```
-Let's loop again over the same dictionary of questions.
+Let's loop again over the same dictionary of questions
-```python PYTHON
+
+```python
for qsn,val in question_dict.items():
print(f'question:{qsn}')
agent_executor.invoke({
@@ -243,64 +268,65 @@ for qsn,val in question_dict.items():
print('-'*50)
```
-```txt title="Output"
-question:q1
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to find the highest value of Cost of Goods and Services Sold from the provided dataframe.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv('income_statement.csv')\n\n# Find the highest value in the 'CostOfGoodsAndServicesSold' column\nmax_value = df['CostOfGoodsAndServicesSold'].max()\n\nprint(f'The highest value of Cost of Goods and Services Sold is {max_value:.2f}')\n"}}
-[0m[36;1m[1;3mThe highest value of Cost of Goods and Services Sold is 169559000000.00
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The highest value of Cost of Goods and Services Sold is 169559000000.00.
-Grounded answer: The highest value of Cost of Goods and Services Sold is 169559000000.00.[0m
-
-[1m> Finished chain.[0m
-GT Answer:169559000000
---------------------------------------------------
-question:q2
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to calculate the largest gross profit margin from the data frame provided.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the gross profit margin as a percentage\ndf[\'GrossProfitMargin\'] = (df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\']) * 100\n\n# Find the row with the maximum gross profit margin\nmax_margin_row = df.loc[df[\'GrossProfitMargin\'].idxmax()]\n\nprint(f"The largest gross profit margin is {max_margin_row[\'GrossProfitMargin\']}% on {max_margin_row[\'index\']}")\n'}}
-[0m[36;1m[1;3mThe largest gross profit margin is 38.36194330595236% on 2019-12-29-2020-03-28
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.
-Grounded answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.[0m
-
-[1m> Finished chain.[0m
-GT Answer:0.3836194330595236
---------------------------------------------------
-question:q3
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to calculate the minimum ratio of Operating Income Loss divided by Non Operating Income Expense.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv('income_statement.csv')\n\n# Calculate the ratio\nratios = df['OperatingIncomeLoss'] / df['NonoperatingIncomeExpense']\n\n# Find the minimum ratio\nmin_ratio = ratios.min()\n\nprint(f'Minimum ratio: {min_ratio:.2f}')\n"}}
-[0m[36;1m[1;3mMinimum ratio: 35.36
-[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.
-Grounded answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.[0m
-
-[1m> Finished chain.[0m
-GT Answer:35.360599
---------------------------------------------------
-```
+ question:q1
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to find the highest value of Cost of Goods and Services Sold from the provided dataframe.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv('income_statement.csv')\n\n# Find the highest value in the 'CostOfGoodsAndServicesSold' column\nmax_value = df['CostOfGoodsAndServicesSold'].max()\n\nprint(f'The highest value of Cost of Goods and Services Sold is {max_value:.2f}')\n"}}
+ [0m[36;1m[1;3mThe highest value of Cost of Goods and Services Sold is 169559000000.00
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The highest value of Cost of Goods and Services Sold is 169559000000.00.
+ Grounded answer: The highest value of Cost of Goods and Services Sold is 169559000000.00.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:169559000000
+ --------------------------------------------------
+ question:q2
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to calculate the largest gross profit margin from the data frame provided.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv(\'income_statement.csv\')\n\n# Calculate the gross profit margin as a percentage\ndf[\'GrossProfitMargin\'] = (df[\'GrossProfit\'] / df[\'RevenueFromContractWithCustomerExcludingAssessedTax\']) * 100\n\n# Find the row with the maximum gross profit margin\nmax_margin_row = df.loc[df[\'GrossProfitMargin\'].idxmax()]\n\nprint(f"The largest gross profit margin is {max_margin_row[\'GrossProfitMargin\']}% on {max_margin_row[\'index\']}")\n'}}
+ [0m[36;1m[1;3mThe largest gross profit margin is 38.36194330595236% on 2019-12-29-2020-03-28
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.
+ Grounded answer: The largest gross profit margin is approximately 38.36% on 2019-12-29 to 2020-03-28.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:0.3836194330595236
+ --------------------------------------------------
+ question:q3
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to calculate the minimum ratio of Operating Income Loss divided by Non Operating Income Expense.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Read the CSV file into a DataFrame\ndf = pd.read_csv('income_statement.csv')\n\n# Calculate the ratio\nratios = df['OperatingIncomeLoss'] / df['NonoperatingIncomeExpense']\n\n# Find the minimum ratio\nmin_ratio = ratios.min()\n\nprint(f'Minimum ratio: {min_ratio:.2f}')\n"}}
+ [0m[36;1m[1;3mMinimum ratio: 35.36
+ [0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.
+ Grounded answer: The minimum ratio of Operating Income Loss divided by Non Operating Income Expense is approximately **35.36**.[0m
+
+ [1m> Finished chain.[0m
+ GT Answer:35.360599
+ --------------------------------------------------
+
Also in this case, the Agent correctly answers all the questions.
-# QnA over Multiple Tables [#sec_step3]
+
+# QnA over Multiple Tables
We now make the task for the Agent more complicated, by asking it questions whose answer can be computed only by retrieving relevant information from multiple tables.
-```python PYTHON
+
+```python
# define the Agent
python_repl = PythonREPL()
python_tool = Tool(
@@ -313,7 +339,7 @@ python_tool.name = "python_interpreter"
class ToolInput(BaseModel):
code: str = Field(description="Python code to execute.")
python_tool.args_schema = ToolInput
-tools=[python_tool]
+tools=[python_tool]
prompt = ChatPromptTemplate.from_template("{input}")
agent = create_cohere_react_agent(
@@ -339,17 +365,19 @@ Here is a preview of the `balance_sheet.csv` dataframe:
```
-We now define a new question.
+We now define a new question
-```python PYTHON
+
+```python
question_dict ={
'q1': ['what is the ratio of the largest stockholders equity to the smallest revenue'],
}
```
-The answer to this question can be obtained only by accessing both the balance sheet and the income statement, as shown below:
+The answer to this question can be obtained only by accessing both the balance sheet and the income statement, as show below:
+
-```python PYTHON
+```python
# get the largest stockholders equity
x = balance_sheet['StockholdersEquity'].astype(float).max()
print(f"The largest stockholders equity value is: {x}")
@@ -363,15 +391,15 @@ ratio = x/y
print(f"Their ratio is: {ratio}")
```
-```txt title="Output"
-The largest stockholders equity value is: 134047000000.0
-The smallest revenue value is: 53809000000.0
-Their ratio is: 2.4911631883142227
-```
+ The largest stockholders equity value is: 134047000000.0
+ The smallest revenue value is: 53809000000.0
+ Their ratio is: 2.4911631883142227
+
-Let's now get the answer from the Agent.
+Let's now get the answer from the Agent
-```python PYTHON
+
+```python
for qsn,val in question_dict.items():
print(f'question:{qsn}')
agent_executor.invoke({
@@ -380,27 +408,31 @@ for qsn,val in question_dict.items():
})
```
-```txt title="Output"
-question:q1
-
-
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write and execute Python code to find the largest and smallest values in the relevant columns of the dataframes, then calculate the ratio.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\nincome_statement = pd.read_csv('income_statement.csv')\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max([balance_sheet['StockholdersEquity'].iloc[i] for i in range(len(balance_sheet))])\nmin_revenue = min([income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'].iloc[i] for i in range(len(income_statement))])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}'\n )"}}
-[0m[36;1m[1;3mNameError("name 'balance_sheet' is not defined")[0m[32;1m[1;3m
-My code has thrown an error because the variable `balance_sheet` has not been defined. I will fix this by adding the line `balance_sheet = pd.read_csv('balance_sheet.csv')` to the beginning of my code.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\nincome_statement = pd.read_csv('income_statement.csv')\n\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max([balance_sheet['StockholdersEquity'].iloc[i] for i in range(len(balance_sheet))])\nmin_revenue = min([income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'].iloc[i] for i in range(len(income_statement))])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}'\n )"}}
-[0m[36;1m[1;3mNameError("name 'balance_sheet' is not defined")[0m[32;1m[1;3m
-The same error has occurred again, so I will check my code carefully to make sure the variable is being defined correctly.
-{'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Load data\nincome_statement = pd.read_csv('income_statement.csv')\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max(balance_sheet['StockholdersEquity'])\nmin_revenue = min(income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}')"}}
-[0m[36;1m[1;3mThe ratio of the largest stockholders equity to the smallest revenue is 2.49
-[0m[32;1m[1;3mRelevant Documents: 0,1,2
-Cited Documents: 2
-Answer: The ratio of the largest stockholders equity to the smallest revenue is approximately **2.49**.
-Grounded answer: The ratio of the largest stockholders equity to the smallest revenue is approximately **2.49**.[0m
-
-[1m> Finished chain.[0m
-```
+ question:q1
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write and execute Python code to find the largest and smallest values in the relevant columns of the dataframes, then calculate the ratio.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\nincome_statement = pd.read_csv('income_statement.csv')\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max([balance_sheet['StockholdersEquity'].iloc[i] for i in range(len(balance_sheet))])\nmin_revenue = min([income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'].iloc[i] for i in range(len(income_statement))])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}'\n )"}}
+ [0m[36;1m[1;3mNameError("name 'balance_sheet' is not defined")[0m[32;1m[1;3m
+ My code has thrown an error because the variable `balance_sheet` has not been defined. I will fix this by adding the line `balance_sheet = pd.read_csv('balance_sheet.csv')` to the beginning of my code.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\nincome_statement = pd.read_csv('income_statement.csv')\n\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max([balance_sheet['StockholdersEquity'].iloc[i] for i in range(len(balance_sheet))])\nmin_revenue = min([income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'].iloc[i] for i in range(len(income_statement))])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}'\n )"}}
+ [0m[36;1m[1;3mNameError("name 'balance_sheet' is not defined")[0m[32;1m[1;3m
+ The same error has occurred again, so I will check my code carefully to make sure the variable is being defined correctly.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': "import pandas as pd\n\n# Load data\nincome_statement = pd.read_csv('income_statement.csv')\nbalance_sheet = pd.read_csv('balance_sheet.csv')\n\n# Find largest and smallest values in relevant columns\nmax_stockholders_equity = max(balance_sheet['StockholdersEquity'])\nmin_revenue = min(income_statement['RevenueFromContractWithCustomerExcludingAssessedTax'])\n\n# Calculate ratio\nratio = max_stockholders_equity / min_revenue\n\nprint(f'The ratio of the largest stockholders equity to the smallest revenue is {ratio:.2f}')"}}
+ [0m[36;1m[1;3mThe ratio of the largest stockholders equity to the smallest revenue is 2.49
+ [0m[32;1m[1;3mRelevant Documents: 0,1,2
+ Cited Documents: 2
+ Answer: The ratio of the largest stockholders equity to the smallest revenue is approximately **2.49**.
+ Grounded answer: The ratio of the largest stockholders equity to the smallest revenue is approximately **2.49**.[0m
+
+ [1m> Finished chain.[0m
+
The Agent defined a plan ("write and execute Python code to find the largest and smallest values in the relevant columns of the dataframes, then calculate the ratio") and executed it. It made some mistakes when coding, that resulted in NameError errors, but it fixed them and finally got to the correct answer
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/data-analyst-agent.mdx b/fern/pages/cookbooks/data-analyst-agent.mdx
index f23b76f9b..378153893 100644
--- a/fern/pages/cookbooks/data-analyst-agent.mdx
+++ b/fern/pages/cookbooks/data-analyst-agent.mdx
@@ -3,55 +3,65 @@ title: A Data Analyst Agent Built with Cohere and Langchain
slug: /page/data-analyst-agent
description: "This page describes how to build a data-analysis system out of Cohere's models."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI agents, automated data analysis"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-Tool use is a method which allows developers to connect Cohere's Command models to external tools like search engines, APIs, databases, and other software tools. Just like how [Retrieval-Augmented Generation (RAG)](https://docs.cohere.com/docs/retrieval-augmented-generation-rag) allows a model to use an external data source to improve factual generation, tool use is a capability that allows retrieving data from multiple sources. But it goes beyond simply retrieving information and is able to use software tools to execute code, or even create entries in a CRM system.
+
+
+
+
+
+
+
+
+Tool use is a method whichs allows developers to connect Cohere's Command models to external tools like search engines, APIs, databases, and other software tools. Just like how [Retrieval-Augmented Generation (RAG)](https://docs.cohere.com/docs/retrieval-augmented-generation-rag) allows a model to use an external data source to improve factual generation, tool use is a capability that allows retrieving data from multiple sources. But it goes beyond simply retrieving information and is able to use software tools to execute code, or even create entries in a CRM system.
In this notebook, we'll see how we can use two tools to create a simple data analyst agent that is able to search the web and run code in a python interpreter. This agent uses Cohere's Command R+ mode and Langchain.
-
+
+
+# Environment
Let's start by installing the required libraries
-```python PYTHON
+
+```python
! pip install --quiet langchain langchain_cohere langchain_experimental
```
## Setup
-
We'll need a Cohere API key here. Grab your key and paste it in the next slide if you have one, or [register](https://dashboard.cohere.ai/welcome/register) and create a new API key.
-```python PYTHON
+
+```python
### LLMs
import os
-os.environ['COHERE_API_KEY'] = ""
+os.environ['COHERE_API_KEY'] = ""
```
-```python PYTHON
+
+```python
+# Create the Cohere chat model
from langchain_cohere.chat_models import ChatCohere
chat = ChatCohere(model="command-r-plus", temperature=0.3)
```
+# Define tools
Our simple data analyst will be equipped with a web search tool, and a python interpreter (which we can use to run plotting code, for example).
### Web search
+Let's first equip our agent with web search! We can use the Tivaly API for this. Head on to [tavily.com](https://tavily.com) and grab an API key to use here.
-Let's first equip our agent with web search! We can use the Tavily API for this. Head on to [tavily.com](https://tavily.com) and grab an API key to use here.
-```python PYTHON
+```python
from langchain_community.tools.tavily_search import TavilySearchResults
-os.environ['TAVILY_API_KEY'] = ""
+os.environ['TAVILY_API_KEY'] = ""
internet_search = TavilySearchResults()
internet_search.name = "internet_search"
@@ -65,10 +75,10 @@ internet_search.args_schema = TavilySearchInput
```
### Python interpreter tool
-
Let's equip our agent with a python interpreter!
-```python PYTHON
+
+```python
from langchain.agents import Tool
from langchain_experimental.utilities import PythonREPL
@@ -80,22 +90,34 @@ repl_tool = Tool(
)
repl_tool.name = "python_interpreter"
+# from langchain_core.pydantic_v1 import BaseModel, Field
class ToolInput(BaseModel):
code: str = Field(description="Python code to execute.")
repl_tool.args_schema = ToolInput
```
-```python PYTHON
+
+```python
+
+```
+
+# Create ReAct Agent: the data analyst
+
+
+```python
from langchain.agents import AgentExecutor
from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
from langchain_core.prompts import ChatPromptTemplate
```
-```python PYTHON
+
+```python
+# Create the prompt
prompt = ChatPromptTemplate.from_template("{input}")
+# Create the ReAct agent
agent = create_cohere_react_agent(
llm=chat,
tools=[internet_search, repl_tool],
@@ -103,100 +125,118 @@ agent = create_cohere_react_agent(
)
```
-```python PYTHON
+
+```python
agent_executor = AgentExecutor(agent=agent, tools=[internet_search, repl_tool], verbose=True)
```
-```python PYTHON
+# Let's ask a question to the data analyst
+
+
+```python
agent_executor.invoke({
"input": "Create a plot of the number of full time employees at the 3 tech companies with the highest market cap in the United States in 2024.",
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-First, I will search for the three tech companies with the highest market cap in the US in 2024. Then, I will search for the number of full-time employees at each of these companies, and plot the data using Python.
-{'tool_name': 'internet_search', 'parameters': {'query': 'top 3 tech companies highest market cap US 2024'}}
-[0m[36;1m[1;3m[{'url': 'https://www.fool.com/research/largest-companies-by-market-cap/', 'content': "It's the most valuable automaker in the world and has the world's best-selling car in the Model Y.\nTesla is most famous for its vehicles, and it's second only to China's BYD Company (OTC:BYDDY) among the largest EV companies in terms of manufacturing. While it's most famous for Windows, Microsoft also has a diverse selection of products and services that has helped to build on its success, including:\nMicrosoft has been the world's largest company before, and it briefly surpassed Apple for the biggest market cap in 2021. Walmart\nWalmart (NYSE:WMT) may not have the largest market cap, but it is No. 1 in terms of revenue, and it’s the largest retailer in the world. Microsoft\nConsidering the popularity of the Windows operating system, it’s no surprise that Microsoft (NASDAQ:MSFT) has consistently ranked as one of the largest companies in the world. Although the top spot has changed hands on multiple occasions, Apple has spent the most time there and is currently the most valuable company in the world.\n"}, {'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://www.statista.com/statistics/1350976/leading-tech-companies-worldwide-by-market-cap/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicAI chips\nHardware\nLeading semiconductor companies worldwide 2023, by market cap\nHardware\nSemiconductor market revenue growth worldwide 1988-2024\nHardware\nNvidia revenue worldwide 2015-2023, by segment\nHardware\nSemiconductor market size worldwide 2020-2030, by application\nYou only have access to basic statistics.\n Other statistics that may interest you\nOther statistics that may interest you Statistics on\nAbout the industry\nAbout the region\nOther regions\nRelated statistics\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nLeading tech companies worldwide 2023, by market cap\nApple\nSamsung\nLeading tech companies worldwide 2023, by market capitalization\n(in billion U.S. dollars)\n Additional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nAugust 2023\nWorldwide\n2023\n'}, {'url': 'https://www.forbes.com/advisor/investing/best-tech-stocks/', 'content': 'eToro\nThe Best Tech Stocks of November 2023\nApple Inc. (AAPL)\n$2.8 trillion\n0.5%\n27.1%\n$2.8 trillion\n0.5%\n27.1%\nApple\xa0 was founded in Los Altos, Calif., by Steve Jobs and Steve Wozniak in 1976. ASML Holding NV (ASML)\n$248 billion\n1.0%\n22.8%\n$248 billion\n1.0%\n22.8%\nASML is a Netherlands-based company that designs and manufactures the machinery used by companies that make microchips. Taiwan Semiconductor Manufacturing Company (TSM)\n$443 billion\n2.0%\n20.6%\n$443 billion\n2.0%\n20.6%\nTaiwan Semiconductor Manufacturing Company could be the biggest tech company you’ve never heard of. NVIDIA Corp (NVDA)\n$1.1 trillion\n0.0%\n62.8%\n$1.1 trillion\n0.0%\n62.8%\nNVIDIA was founded in 1993 to produce graphic cards for the burgeoning personal computer market. Microsoft Corporation (MSFT)\n$2.6 trillion\n0.8%\n27.3%\n$2.6 trillion\n0.8%\n27.3%\nMicrosoft\xa0 was founded in 1975 by Bill Gates and Paul Allen in Albuquerque, N.M.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}][0m[32;1m[1;3m
-I have found that the three tech companies with the highest market cap in the US in 2024 are Microsoft, Apple and NVIDIA. Now, I will search for the number of full-time employees at each of these companies and plot the data.
-{'tool_name': 'internet_search', 'parameters': {'query': 'Microsoft full time employees 2024'}}
-[0m[36;1m[1;3m[{'url': 'https://www.statista.com/statistics/273475/number-of-employees-at-the-microsoft-corporation-since-2005/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicMicrosoft\nSoftware\nMicrosoft\'s expenditure on research and development 2002-2023\nSoftware\nOffice productivity software market share worldwide 2022\nIT Services\nCloud infrastructure services market share quarterly worldwide 2017-2022, by vendor\nSoftware\nMicrosoft\'s revenue 2008-2024, by fiscal quarter\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Statistics on\n"\nMicrosoft\n"\nOther statistics that may interest you Microsoft\nOverview\nCompany financials\nSegments\nCompetitors: Software\nCompetitors: Cloud\nCompetitors: Devices\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Number of Microsoft employees 2005-2023\nHow many employees does Microsoft have?\nNumber of employees at the Microsoft Corporation from 2005 to 2023\n(in 1,000s)\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nJuly 2023\nWorldwide\n2005 to 2023\nMicrosoft\'s fiscal year ends on June 30.\n Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://stockanalysis.com/stocks/msft/employees/', 'content': "MSFT News. 1 day ago - Microsoft Pushes LinkedIn Further Into the Connected Economy - PYMNTS 1 day ago - Softchoice to Advance Generative AI and Security Solutions Through New Agreement With Microsoft - Business Wire 1 day ago - AMD, Samsung, Check Point, Microsoft, and Other Tech Stocks in Focus Today - Barrons 1 day ago - Don't chase the value rebound, tech still has a few surprises up its ..."}, {'url': 'https://www.macrotrends.net/stocks/charts/MSFT/microsoft/number-of-employees', 'content': 'Interactive chart of Microsoft (MSFT) annual worldwide employee count from 2010 to 2023. Microsoft total number of employees in 2023 was 221,000, a 0% decline from 2022. Microsoft total number of employees in 2022 was 221,000, a 22.1% increase from 2021. Microsoft total number of employees in 2021 was 181,000, a 11.04% increase from 2020.'}, {'url': 'https://www.microsoft.com/investor/reports/ar23/index.html', 'content': 'As of June 30, 2023, we employed approximately 221,000 people on a full-time basis, 120,000 in the U.S. and 101,000 internationally. Of the total employed people, 89,000 were in operations, including manufacturing, distribution, product support, and consulting services; 72,000 were in product research and development; 45,000 were in sales and ...'}, {'url': 'https://www.microsoft.com/en-us/investor/earnings/fy-2024-q2/press-release-webcast', 'content': 'Microsoft Cloud Strength Drives Second Quarter Results. REDMOND, Wash. — January 30, 2024 — Microsoft Corp. today announced the following results for the quarter ended December 31, 2023, as compared to the corresponding period of last fiscal year: · Revenue was $62.0 billion and increased 18% (up 16% in constant currency) · Operating income was $27.0 billion and increased 33%, and ...'}][0m[32;1m[1;3m
-{'tool_name': 'internet_search', 'parameters': {'query': 'Apple full time employees 2024'}}
-[0m[36;1m[1;3m[{'url': 'https://www.macrotrends.net/stocks/charts/AAPL/apple/number-of-employees', 'content': 'Employee Count. Interactive chart of Apple (AAPL) annual worldwide employee count from 2010 to 2023. Apple total number of employees in 2023 was 161,000, a 1.83% decline from 2022. Apple total number of employees in 2022 was 164,000, a 6.49% increase from 2021. Apple total number of employees in 2021 was 154,000, a 4.76% increase from 2020.'}, {'url': 'https://www.businessinsider.com/apple-layoffs-tim-cook-getting-serious-challenges-car-china-iphone-2024-4?op=1', 'content': "2024-04-05T12:27:33Z An curved arrow pointing right. Share. The ... That's especially so when considering that Apple had about 161,000 full-time employees at the end of its last fiscal year."}, {'url': 'https://www.statista.com/statistics/273439/number-of-employees-of-apple-since-2005/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicApple\nConsumer Electronics\nApple\'s revenue worldwide 2004-2023\nConsumer Electronics\nApple\'s revenue broken down by geographical region 2012-2023, by quarter\nTelecommunications\nQuarterly market share of smartphone vendors in the U.S. 2016-2023\nConsumer Electronics\nApple: expenditure on research and development 2007-2023\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Statistics on\n"\nApple in the U.S.\n"\nOther statistics that may interest you Apple in the U.S.\nOverview: Apple\nOverview: Apple in the U.S.\nSegment: iPhone\nSegment: iPad\nSegment: Mac\nSegment: Wearables & Smart home\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Number of employees of Apple 2005-2023\nApple Corporation – additional information\nApple products\nApple\'s number of employees in the fiscal years 2005 to 2023\n(in 1,000s)\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nNovember 2023\nWorldwide\n2005 to 2023\n Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://jobs.apple.com/en-us/details/200542480/fy-24-full-time-opportunity-for-fresh-graduates-general', 'content': "Shop and Learn\nServices\nAccount\nApple Store\nFor Business\nFor Education\nFor Healthcare\nFor Government\nApple Values\nAbout Apple Summary\nKey Qualifications\nDescription\nEducation & Experience\nAdditional Requirements\nAdd a favorite\nDon’t have an Apple ID?\nApple Footer\nApple is an equal opportunity employer that is committed to inclusion and diversity. If you’re applying for a position in San Francisco,review the\nSan Francisco Fair Chance Ordinance guidelines (opens in a new window)\napplicable in your area.\n FY'24 Full Time Opportunity for Fresh Graduates - General\nAdd a favorite\nDon’t have an Apple ID?\n Learn more about your EEO rights as an applicant (Opens in a new window) .\n"}, {'url': 'https://jobs.apple.com/en-us/details/200544662/wiml-2024-full-time-opportunities-at-apple', 'content': 'Shop and Learn\nServices\nAccount\nApple Store\nFor Business\nFor Education\nFor Healthcare\nFor Government\nApple Values\nAbout Apple Summary\nKey Qualifications\nDescription\nEducation & Experience\nAdditional Requirements\nAdd a favorite\nDon’t have an Apple ID?\nApple Footer\nApple is an equal opportunity employer that is committed to inclusion and diversity. If you’re applying for a position in San Francisco,review the\nSan Francisco Fair Chance Ordinance guidelines (opens in a new window)\napplicable in your area.\n WiML 2024 - Full Time Opportunities at Apple\nAdd a favorite\nDon’t have an Apple ID?\n Learn more about your EEO rights as an applicant (Opens in a new window) .\n'}][0m[32;1m[1;3m
-{'tool_name': 'internet_search', 'parameters': {'query': 'NVIDIA full time employees 2024'}}
-[0m[36;1m[1;3m[{'url': 'https://www.macrotrends.net/stocks/charts/NVDA/nvidia/number-of-employees', 'content': 'Employee Count. Interactive chart of NVIDIA (NVDA) annual worldwide employee count from 2010 to 2024. NVIDIA total number of employees in 2024 was 29,600, a 12.99% increase from 2023. NVIDIA total number of employees in 2023 was 26,196, a 16.57% increase from 2022. NVIDIA total number of employees in 2022 was 22,473, a 18.43% increase from 2021.'}, {'url': 'https://www.statista.com/statistics/1369575/nvidia-number-of-employees-by-region/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicNvidia\nHardware\nSemiconductor market revenue worldwide 1987-2024\nHardware\nLeading semiconductor companies worldwide 2024, by market cap\nHardware\nSemiconductor companies market revenue share worldwide 2008-2023\nHardware\nSemiconductor market revenue growth worldwide 1988-2024\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Nvidia number of employees 2023, by region\nNvidia number of employees in 2023, by region\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nJuly 2023\nWorldwide\n2023\nIncludes full-time and part-time employees.\n Statistics on\n"\nNvidia\n"\nOther statistics that may interest you Nvidia\nOverview\nFinancials\nSegments\nESG\nCompetitors\nFurther Content: You might find this interesting as well\nTopics Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://finance.yahoo.com/news/nvidia-announces-financial-results-fourth-212000202.html', 'content': "Proceeds related to employee stock plans\n-\n5\n403\n355\nPayments related to repurchases of common stock\n(2,660\n)\n(1,212\n)\n(9,533\n)\n(10,039\n)\nPayments related to tax on restricted stock units\n(841\n)\n(344\n)\n(2,783\n)\n(1,475\n)\nRepayment of debt\n-\n-\n(1,250\n)\n-\nDividends paid\n(99\n)\n(98\n)\n(395\n)\n(398\n)\nPrincipal payments on property and equipment and intangible assets\n(29\n)\n(4\n)\n(74\n)\n(58\n)\nOther\n-\n(3\n)\n(1\n)\n(2\n)\nNet cash used in financing activities\n(3,629\n)\n(1,656\n)\n(13,633\n)\n(11,617\n)\nChange in cash and cash equivalents\n1,761\n589\n3,891\n1,399\nCash and cash equivalents at beginning of period\n5,519\n2,800\n3,389\n1,990\nCash and cash equivalents at end of period\n$\n7,280\n$\n3,389\n$\n7,280\n$\n3,389\nSupplemental disclosures of cash flow information:\nCash paid for income taxes, net\n$\n1,874\n$\n32\n$\n6,549\n$\n1,404\nCash paid for interest\n$\n26\n$\n28\n$\n252\n$\n254\nNVIDIA CORPORATION\nRECONCILIATION OF GAAP TO NON-GAAP FINANCIAL MEASURES\n(In millions, except per share data)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nOctober 29,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2023\n2024\n2023\nGAAP gross profit\n$\n16,791\n$\n13,400\n$\n3,833\n$\n44,301\n$\n15,356\nGAAP gross margin\n76.0\n%\n74.0\n%\n63.3\n%\n72.7\n%\n56.9\n%\nAcquisition-related and other costs (A)\n119\n119\n120\n477\n455\nStock-based compensation expense (B)\n45\n38\n30\n141\n138\nIP-related costs\n4\n26\n16\n40\n16\nNon-GAAP gross profit\n$\n16,959\n$\n13,583\n$\n3,999\n$\n44,959\n$\n15,965\nNon-GAAP gross margin\n76.7\n%\n75.0\n%\n66.1\n%\n73.8\n%\n59.2\n%\nGAAP operating expenses\n$\n3,176\n$\n2,983\n$\n2,576\n$\n11,329\n$\n11,132\nStock-based compensation expense (B)\n(948\n)\n(941\n)\n(709\n)\n(3,408\n)\n(2,572\n)\nAcquisition-related and other costs (A)\n(18\n)\n(16\n)\n(54\n)\n(106\n)\n(219\n)\nAcquisition termination cost\n-\n-\n-\n-\n(1,353\n)\nOther (C)\n-\n-\n(38\n)\n10\n(63\n)\nNon-GAAP operating expenses\n$\n2,210\n$\n2,026\n$\n1,775\n$\n7,825\n$\n6,925\nGAAP operating income\n$\n13,615\n$\n10,417\n$\n1,257\n$\n32,972\n$\n4,224\nTotal impact of non-GAAP adjustments to operating income\n1,134\n1,140\n967\n4,162\n4,816\nNon-GAAP operating income\n$\n14,749\n$\n11,557\n$\n2,224\n$\n37,134\n$\n9,040\nGAAP other income (expense), net\n$\n491\n$\n105\n$\n32\n$\n846\n$\n(43\n)\n(Gains) losses from non-affiliated investments\n(260\n)\n69\n10\n(238\n)\n45\nInterest expense related to amortization of debt discount\n1\n1\n1\n4\n5\nNon-GAAP other income (expense), net\n$\n232\n$\n175\n$\n43\n$\n612\n$\n7\nGAAP net income\n$\n12,285\n$\n9,243\n$\n1,414\n$\n29,760\n$\n4,368\nTotal pre-tax impact of non-GAAP adjustments\n875\n1,210\n978\n3,928\n4,865\nIncome tax impact of non-GAAP adjustments (D)\n(321\n)\n(433\n)\n(218\n)\n(1,376\n)\n(867\n)\n Other, net\n260\n(18\n)\n237\n(48\n)\nOther income (expense), net\n491\n32\n846\n(43\n)\nIncome before income tax\n14,106\n1,289\n33,818\n4,181\nIncome tax expense (benefit)\n1,821\n(125\n)\n4,058\n(187\n)\nNet income\n$\n12,285\n$\n1,414\n$\n29,760\n$\n4,368\nNet income per share:\nBasic\n$\n4.98\n$\n0.57\n$\n12.05\n$\n1.76\nDiluted\n$\n4.93\n$\n0.57\n$\n11.93\n$\n1.74\nWeighted average shares used in per share computation:\nBasic\n2,466\n2,464\n2,469\n2,487\nDiluted\n2,490\n2,477\n2,494\n2,507\nNVIDIA CORPORATION\nCONDENSED CONSOLIDATED BALANCE SHEETS\n(In millions)\n(Unaudited)\nJanuary 28,\nJanuary 29,\n2024\n2023\nASSETS\nCurrent assets:\nCash, cash equivalents and marketable securities\n$\n25,984\n$\n13,296\nAccounts receivable, net\n9,999\n3,827\nInventories\n5,282\n5,159\nPrepaid expenses and other current assets\n3,080\n791\nTotal current assets\n44,345\n23,073\nProperty and equipment, net\n3,914\n3,807\nOperating lease assets\n1,346\n1,038\nGoodwill\n4,430\n4,372\nIntangible assets, net\n1,112\n1,676\nDeferred income tax assets\n6,081\n3,396\nOther assets\n4,500\n3,820\nTotal assets\n$\n65,728\n$\n41,182\nLIABILITIES AND SHAREHOLDERS' EQUITY\nCurrent liabilities:\nAccounts payable\n$\n2,699\n$\n1,193\nAccrued and other current liabilities\n6,682\n4,120\nShort-term debt\n1,250\n1,250\nTotal current liabilities\n10,631\n6,563\nLong-term debt\n8,459\n9,703\nLong-term operating lease liabilities\n1,119\n902\nOther long-term liabilities\n2,541\n1,913\nTotal liabilities\n22,750\n19,081\nShareholders' equity\n42,978\n22,101\nTotal liabilities and shareholders' equity\n$\n65,728\n$\n41,182\nNVIDIA CORPORATION\nCONDENSED CONSOLIDATED STATEMENTS OF CASH FLOWS\n(In millions)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2024\n2023\nCash flows from operating activities:\nNet income\n$\n12,285\n$\n1,414\n$\n29,760\n$\n4,368\nAdjustments to reconcile net income to net cash\nprovided by operating activities:\nStock-based compensation expense\n993\n738\n3,549\n2,709\nDepreciation and amortization\n387\n426\n1,508\n1,544\nDeferred income taxes\n(78\n)\n(647\n)\n(2,489\n)\n(2,164\n)\n(Gains) losses on investments in non-affiliated entities, net\n(260\n)\n10\n(238\n)\n45\nAcquisition termination cost\n-\n-\n-\n1,353\nOther\n(109\n)\n20\n(278\n)\n(7\n)\nChanges in operating assets and liabilities, net of acquisitions:\n Q4 Fiscal 2024 Summary\nGAAP\n($ in millions, except earnings per share)\nQ4 FY24\nQ3 FY24\nQ4 FY23\nQ/Q\nY/Y\nRevenue\n$22,103\n$18,120\n$6,051\nUp 22%\nUp 265%\nGross margin\n76.0%\n74.0%\n63.3%\nUp 2.0 pts\nUp 12.7 pts\nOperating expenses\n$3,176\n$2,983\n$2,576\nUp 6%\nUp 23%\nOperating income\n$13,615\n$10,417\n$1,257\nUp 31%\nUp 983%\nNet income\n$12,285\n$9,243\n$1,414\nUp 33%\nUp 769%\nDiluted earnings per share\n$4.93\n$3.71\n$0.57\nUp 33%\nUp 765%\nNon-GAAP\n($ in millions, except earnings per share)\nQ4 FY24\nQ3 FY24\nQ4 FY23\nQ/Q\nY/Y\nRevenue\n$22,103\n$18,120\n$6,051\nUp 22%\nUp 265%\nGross margin\n76.7%\n75.0%\n66.1%\nUp 1.7 pts\nUp 10.6 pts\nOperating expenses\n$2,210\n$2,026\n$1,775\nUp 9%\nUp 25%\nOperating income\n$14,749\n$11,557\n$2,224\nUp 28%\nUp 563%\nNet income\n$12,839\n$10,020\n$2,174\nUp 28%\nUp 491%\nDiluted earnings per share\n$5.16\n$4.02\n$0.88\nUp 28%\nUp 486%\nFiscal 2024 Summary\nGAAP\n($ in millions, except earnings per share)\n 2024\n2023\n2023\n2024\n2023\nCost of revenue\n$\n119\n$\n119\n$\n120\n$\n477\n$\n455\nResearch and development\n$\n12\n$\n12\n$\n10\n$\n49\n$\n39\nSales, general and administrative\n$\n6\n$\n4\n$\n44\n$\n57\n$\n180\n(B) Stock-based compensation consists of the following:\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nOctober 29,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2023\n2024\n2023\nCost of revenue\n$\n45\n$\n38\n$\n30\n$\n141\n$\n138\nResearch and development\n$\n706\n$\n701\n$\n527\n$\n2,532\n$\n1,892\nSales, general and administrative\n NVIDIA CORPORATION\nCONDENSED CONSOLIDATED STATEMENTS OF INCOME\n(In millions, except per share data)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2024\n2023\nRevenue\n$\n22,103\n$\n6,051\n$\n60,922\n$\n26,974\nCost of revenue\n5,312\n2,218\n16,621\n11,618\nGross profit\n16,791\n3,833\n44,301\n15,356\nOperating expenses\nResearch and development\n2,465\n1,951\n8,675\n7,339\nSales, general and administrative\n711\n625\n2,654\n2,440\nAcquisition termination cost\n-\n-\n-\n1,353\nTotal operating expenses\n3,176\n2,576\n11,329\n11,132\nOperating Income\n13,615\n1,257\n32,972\n4,224\nInterest income\n294\n115\n866\n267\nInterest expense\n(63\n)\n(65\n)\n(257\n)\n(262\n)\n"}, {'url': 'https://stockanalysis.com/stocks/nvda/employees/', 'content': 'NVIDIA had 29,600 employees on January 28, 2024. The number of employees increased by 3,404 or 12.99% compared to the previous year. Employees 29,600. Change (1Y) 3,404. ... Real-time quotes provided by IEX Cloud. Other market data may be delayed by 15 minutes or more. ...'}, {'url': 'https://investor.nvidia.com/news/press-release-details/2024/NVIDIA-Announces-Financial-Results-for-Fourth-Quarter-and-Fiscal-2024/?ref=robotradingnet.ghost.io', 'content': 'SANTA CLARA, Calif., Feb. 21, 2024 (GLOBE NEWSWIRE) -- NVIDIA (NASDAQ: NVDA) today reported revenue for the fourth quarter ended January 28, 2024, of $22.1 billion, up 22% from the previous quarter and up 265% from a year ago. For the quarter, GAAP earnings per diluted share was $4.93, up 33% from the previous quarter and up 765% from a year ...'}][0m[32;1m[1;3m
-I have found the following data on the number of full-time employees at each company:
-Microsoft: 221,000
-Apple: 161,000
-NVIDIA: 29,600
-Now, I will write and execute Python code to plot this data.
-{'tool_name': 'python_interpreter', 'parameters': {'code': 'import matplotlib.pyplot as plt\n\n# Data on the number of full-time employees at each company\ncompanies = [\n "Microsoft", "Apple", "NVIDIA"\n]\nfull_time_employees = [221000, 161000, 29600]\n\n# Plot the data\nplt.bar(companies, full_time_employees)\nplt.xlabel("Company")\nplt.ylabel("Number of Full Time Employees")\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.savefig("tech_companies_market_cap_employees.png")'}}
-[0m[33;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0,1,3,4,5,7,8,9,10,11,12,15,18,20
-Cited Documents: 1,3,4,7,8,10,11,15,18,20
-Answer: Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:
-
-
-
-The companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.
-Grounded answer: Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:
-! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')
-
-The companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.[0m
-
-[1m> Finished chain.[0m
-
-
-
-
-
-{'input': 'Create a plot of the number of full time employees at the 3 tech companies with the highest market cap in the United States in 2024.',
- 'output': "Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:\n! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')\n\nThe companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.",
- 'citations': [CohereCitation(start=125, end=201, text="! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')", documents=[{'output': ''}]),
- CohereCitation(start=268, end=277, text='Microsoft', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
- CohereCitation(start=283, end=290, text='221,000', documents=[{'url': 'https://www.microsoft.com/investor/reports/ar23/index.html', 'content': 'As of June 30, 2023, we employed approximately 221,000 people on a full-time basis, 120,000 in the U.S. and 101,000 internationally. Of the total employed people, 89,000 were in operations, including manufacturing, distribution, product support, and consulting services; 72,000 were in product research and development; 45,000 were in sales and ...'}, {'url': 'https://www.macrotrends.net/stocks/charts/MSFT/microsoft/number-of-employees', 'content': 'Interactive chart of Microsoft (MSFT) annual worldwide employee count from 2010 to 2023. Microsoft total number of employees in 2023 was 221,000, a 0% decline from 2022. Microsoft total number of employees in 2022 was 221,000, a 22.1% increase from 2021. Microsoft total number of employees in 2021 was 181,000, a 11.04% increase from 2020.'}]),
- CohereCitation(start=292, end=297, text='Apple', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://www.forbes.com/advisor/investing/best-tech-stocks/', 'content': 'eToro\nThe Best Tech Stocks of November 2023\nApple Inc. (AAPL)\n$2.8 trillion\n0.5%\n27.1%\n$2.8 trillion\n0.5%\n27.1%\nApple\xa0 was founded in Los Altos, Calif., by Steve Jobs and Steve Wozniak in 1976. ASML Holding NV (ASML)\n$248 billion\n1.0%\n22.8%\n$248 billion\n1.0%\n22.8%\nASML is a Netherlands-based company that designs and manufactures the machinery used by companies that make microchips. Taiwan Semiconductor Manufacturing Company (TSM)\n$443 billion\n2.0%\n20.6%\n$443 billion\n2.0%\n20.6%\nTaiwan Semiconductor Manufacturing Company could be the biggest tech company you’ve never heard of. NVIDIA Corp (NVDA)\n$1.1 trillion\n0.0%\n62.8%\n$1.1 trillion\n0.0%\n62.8%\nNVIDIA was founded in 1993 to produce graphic cards for the burgeoning personal computer market. Microsoft Corporation (MSFT)\n$2.6 trillion\n0.8%\n27.3%\n$2.6 trillion\n0.8%\n27.3%\nMicrosoft\xa0 was founded in 1975 by Bill Gates and Paul Allen in Albuquerque, N.M.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
- CohereCitation(start=303, end=310, text='161,000', documents=[{'url': 'https://www.macrotrends.net/stocks/charts/AAPL/apple/number-of-employees', 'content': 'Employee Count. Interactive chart of Apple (AAPL) annual worldwide employee count from 2010 to 2023. Apple total number of employees in 2023 was 161,000, a 1.83% decline from 2022. Apple total number of employees in 2022 was 164,000, a 6.49% increase from 2021. Apple total number of employees in 2021 was 154,000, a 4.76% increase from 2020.'}, {'url': 'https://www.businessinsider.com/apple-layoffs-tim-cook-getting-serious-challenges-car-china-iphone-2024-4?op=1', 'content': "2024-04-05T12:27:33Z An curved arrow pointing right. Share. The ... That's especially so when considering that Apple had about 161,000 full-time employees at the end of its last fiscal year."}]),
- CohereCitation(start=315, end=321, text='NVIDIA', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
- CohereCitation(start=327, end=333, text='29,600', documents=[{'url': 'https://stockanalysis.com/stocks/nvda/employees/', 'content': 'NVIDIA had 29,600 employees on January 28, 2024. The number of employees increased by 3,404 or 12.99% compared to the previous year. Employees 29,600. Change (1Y) 3,404. ... Real-time quotes provided by IEX Cloud. Other market data may be delayed by 15 minutes or more. ...'}, {'url': 'https://www.macrotrends.net/stocks/charts/NVDA/nvidia/number-of-employees', 'content': 'Employee Count. Interactive chart of NVIDIA (NVDA) annual worldwide employee count from 2010 to 2024. NVIDIA total number of employees in 2024 was 29,600, a 12.99% increase from 2023. NVIDIA total number of employees in 2023 was 26,196, a 16.57% increase from 2022. NVIDIA total number of employees in 2022 was 22,473, a 18.43% increase from 2021.'}])]}
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ First, I will search for the three tech companies with the highest market cap in the US in 2024. Then, I will search for the number of full-time employees at each of these companies, and plot the data using Python.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'top 3 tech companies highest market cap US 2024'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.fool.com/research/largest-companies-by-market-cap/', 'content': "It's the most valuable automaker in the world and has the world's best-selling car in the Model Y.\nTesla is most famous for its vehicles, and it's second only to China's BYD Company (OTC:BYDDY) among the largest EV companies in terms of manufacturing. While it's most famous for Windows, Microsoft also has a diverse selection of products and services that has helped to build on its success, including:\nMicrosoft has been the world's largest company before, and it briefly surpassed Apple for the biggest market cap in 2021. Walmart\nWalmart (NYSE:WMT) may not have the largest market cap, but it is No. 1 in terms of revenue, and it’s the largest retailer in the world. Microsoft\nConsidering the popularity of the Windows operating system, it’s no surprise that Microsoft (NASDAQ:MSFT) has consistently ranked as one of the largest companies in the world. Although the top spot has changed hands on multiple occasions, Apple has spent the most time there and is currently the most valuable company in the world.\n"}, {'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://www.statista.com/statistics/1350976/leading-tech-companies-worldwide-by-market-cap/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicAI chips\nHardware\nLeading semiconductor companies worldwide 2023, by market cap\nHardware\nSemiconductor market revenue growth worldwide 1988-2024\nHardware\nNvidia revenue worldwide 2015-2023, by segment\nHardware\nSemiconductor market size worldwide 2020-2030, by application\nYou only have access to basic statistics.\n Other statistics that may interest you\nOther statistics that may interest you Statistics on\nAbout the industry\nAbout the region\nOther regions\nRelated statistics\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nLeading tech companies worldwide 2023, by market cap\nApple\nSamsung\nLeading tech companies worldwide 2023, by market capitalization\n(in billion U.S. dollars)\n Additional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nAugust 2023\nWorldwide\n2023\n'}, {'url': 'https://www.forbes.com/advisor/investing/best-tech-stocks/', 'content': 'eToro\nThe Best Tech Stocks of November 2023\nApple Inc. (AAPL)\n$2.8 trillion\n0.5%\n27.1%\n$2.8 trillion\n0.5%\n27.1%\nApple\xa0 was founded in Los Altos, Calif., by Steve Jobs and Steve Wozniak in 1976. ASML Holding NV (ASML)\n$248 billion\n1.0%\n22.8%\n$248 billion\n1.0%\n22.8%\nASML is a Netherlands-based company that designs and manufactures the machinery used by companies that make microchips. Taiwan Semiconductor Manufacturing Company (TSM)\n$443 billion\n2.0%\n20.6%\n$443 billion\n2.0%\n20.6%\nTaiwan Semiconductor Manufacturing Company could be the biggest tech company you’ve never heard of. NVIDIA Corp (NVDA)\n$1.1 trillion\n0.0%\n62.8%\n$1.1 trillion\n0.0%\n62.8%\nNVIDIA was founded in 1993 to produce graphic cards for the burgeoning personal computer market. Microsoft Corporation (MSFT)\n$2.6 trillion\n0.8%\n27.3%\n$2.6 trillion\n0.8%\n27.3%\nMicrosoft\xa0 was founded in 1975 by Bill Gates and Paul Allen in Albuquerque, N.M.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}][0m[32;1m[1;3m
+ I have found that the three tech companies with the highest market cap in the US in 2024 are Microsoft, Apple and NVIDIA. Now, I will search for the number of full-time employees at each of these companies and plot the data.
+ {'tool_name': 'internet_search', 'parameters': {'query': 'Microsoft full time employees 2024'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.statista.com/statistics/273475/number-of-employees-at-the-microsoft-corporation-since-2005/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicMicrosoft\nSoftware\nMicrosoft\'s expenditure on research and development 2002-2023\nSoftware\nOffice productivity software market share worldwide 2022\nIT Services\nCloud infrastructure services market share quarterly worldwide 2017-2022, by vendor\nSoftware\nMicrosoft\'s revenue 2008-2024, by fiscal quarter\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Statistics on\n"\nMicrosoft\n"\nOther statistics that may interest you Microsoft\nOverview\nCompany financials\nSegments\nCompetitors: Software\nCompetitors: Cloud\nCompetitors: Devices\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Number of Microsoft employees 2005-2023\nHow many employees does Microsoft have?\nNumber of employees at the Microsoft Corporation from 2005 to 2023\n(in 1,000s)\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nJuly 2023\nWorldwide\n2005 to 2023\nMicrosoft\'s fiscal year ends on June 30.\n Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://stockanalysis.com/stocks/msft/employees/', 'content': "MSFT News. 1 day ago - Microsoft Pushes LinkedIn Further Into the Connected Economy - PYMNTS 1 day ago - Softchoice to Advance Generative AI and Security Solutions Through New Agreement With Microsoft - Business Wire 1 day ago - AMD, Samsung, Check Point, Microsoft, and Other Tech Stocks in Focus Today - Barrons 1 day ago - Don't chase the value rebound, tech still has a few surprises up its ..."}, {'url': 'https://www.macrotrends.net/stocks/charts/MSFT/microsoft/number-of-employees', 'content': 'Interactive chart of Microsoft (MSFT) annual worldwide employee count from 2010 to 2023. Microsoft total number of employees in 2023 was 221,000, a 0% decline from 2022. Microsoft total number of employees in 2022 was 221,000, a 22.1% increase from 2021. Microsoft total number of employees in 2021 was 181,000, a 11.04% increase from 2020.'}, {'url': 'https://www.microsoft.com/investor/reports/ar23/index.html', 'content': 'As of June 30, 2023, we employed approximately 221,000 people on a full-time basis, 120,000 in the U.S. and 101,000 internationally. Of the total employed people, 89,000 were in operations, including manufacturing, distribution, product support, and consulting services; 72,000 were in product research and development; 45,000 were in sales and ...'}, {'url': 'https://www.microsoft.com/en-us/investor/earnings/fy-2024-q2/press-release-webcast', 'content': 'Microsoft Cloud Strength Drives Second Quarter Results. REDMOND, Wash. — January 30, 2024 — Microsoft Corp. today announced the following results for the quarter ended December 31, 2023, as compared to the corresponding period of last fiscal year: · Revenue was $62.0 billion and increased 18% (up 16% in constant currency) · Operating income was $27.0 billion and increased 33%, and ...'}][0m[32;1m[1;3m
+ {'tool_name': 'internet_search', 'parameters': {'query': 'Apple full time employees 2024'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.macrotrends.net/stocks/charts/AAPL/apple/number-of-employees', 'content': 'Employee Count. Interactive chart of Apple (AAPL) annual worldwide employee count from 2010 to 2023. Apple total number of employees in 2023 was 161,000, a 1.83% decline from 2022. Apple total number of employees in 2022 was 164,000, a 6.49% increase from 2021. Apple total number of employees in 2021 was 154,000, a 4.76% increase from 2020.'}, {'url': 'https://www.businessinsider.com/apple-layoffs-tim-cook-getting-serious-challenges-car-china-iphone-2024-4?op=1', 'content': "2024-04-05T12:27:33Z An curved arrow pointing right. Share. The ... That's especially so when considering that Apple had about 161,000 full-time employees at the end of its last fiscal year."}, {'url': 'https://www.statista.com/statistics/273439/number-of-employees-of-apple-since-2005/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicApple\nConsumer Electronics\nApple\'s revenue worldwide 2004-2023\nConsumer Electronics\nApple\'s revenue broken down by geographical region 2012-2023, by quarter\nTelecommunications\nQuarterly market share of smartphone vendors in the U.S. 2016-2023\nConsumer Electronics\nApple: expenditure on research and development 2007-2023\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Statistics on\n"\nApple in the U.S.\n"\nOther statistics that may interest you Apple in the U.S.\nOverview: Apple\nOverview: Apple in the U.S.\nSegment: iPhone\nSegment: iPad\nSegment: Mac\nSegment: Wearables & Smart home\nFurther related statistics\nFurther Content: You might find this interesting as well\nStatistics\nTopics Number of employees of Apple 2005-2023\nApple Corporation – additional information\nApple products\nApple\'s number of employees in the fiscal years 2005 to 2023\n(in 1,000s)\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nNovember 2023\nWorldwide\n2005 to 2023\n Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://jobs.apple.com/en-us/details/200542480/fy-24-full-time-opportunity-for-fresh-graduates-general', 'content': "Shop and Learn\nServices\nAccount\nApple Store\nFor Business\nFor Education\nFor Healthcare\nFor Government\nApple Values\nAbout Apple Summary\nKey Qualifications\nDescription\nEducation & Experience\nAdditional Requirements\nAdd a favorite\nDon’t have an Apple ID?\nApple Footer\nApple is an equal opportunity employer that is committed to inclusion and diversity. If you’re applying for a position in San Francisco,review the\nSan Francisco Fair Chance Ordinance guidelines (opens in a new window)\napplicable in your area.\n FY'24 Full Time Opportunity for Fresh Graduates - General\nAdd a favorite\nDon’t have an Apple ID?\n Learn more about your EEO rights as an applicant (Opens in a new window) .\n"}, {'url': 'https://jobs.apple.com/en-us/details/200544662/wiml-2024-full-time-opportunities-at-apple', 'content': 'Shop and Learn\nServices\nAccount\nApple Store\nFor Business\nFor Education\nFor Healthcare\nFor Government\nApple Values\nAbout Apple Summary\nKey Qualifications\nDescription\nEducation & Experience\nAdditional Requirements\nAdd a favorite\nDon’t have an Apple ID?\nApple Footer\nApple is an equal opportunity employer that is committed to inclusion and diversity. If you’re applying for a position in San Francisco,review the\nSan Francisco Fair Chance Ordinance guidelines (opens in a new window)\napplicable in your area.\n WiML 2024 - Full Time Opportunities at Apple\nAdd a favorite\nDon’t have an Apple ID?\n Learn more about your EEO rights as an applicant (Opens in a new window) .\n'}][0m[32;1m[1;3m
+ {'tool_name': 'internet_search', 'parameters': {'query': 'NVIDIA full time employees 2024'}}
+ [0m[36;1m[1;3m[{'url': 'https://www.macrotrends.net/stocks/charts/NVDA/nvidia/number-of-employees', 'content': 'Employee Count. Interactive chart of NVIDIA (NVDA) annual worldwide employee count from 2010 to 2024. NVIDIA total number of employees in 2024 was 29,600, a 12.99% increase from 2023. NVIDIA total number of employees in 2023 was 26,196, a 16.57% increase from 2022. NVIDIA total number of employees in 2022 was 22,473, a 18.43% increase from 2021.'}, {'url': 'https://www.statista.com/statistics/1369575/nvidia-number-of-employees-by-region/', 'content': 'Digital & Trend reports\nOverview and forecasts on trending topics\nIndustry & Market reports\nIndustry and market insights and forecasts\nCompanies & Products reports\nKey figures and rankings about companies and products\nConsumer & Brand reports\nConsumer and brand insights and preferences in various industries\nPolitics & Society reports\nDetailed information about political and social topics\nCountry & Region reports\nAll key figures about countries and regions\nMarket forecast and expert KPIs for 1000+ markets in 190+ countries & territories\nInsights on consumer attitudes and behavior worldwide\nBusiness information on 100m+ public and private companies\nExplore Company Insights\nDetailed information for 39,000+ online stores and marketplaces\nDirectly accessible data for 170 industries from 150+ countries\nand over 1\xa0Mio. facts.\n Other statistics on the topicNvidia\nHardware\nSemiconductor market revenue worldwide 1987-2024\nHardware\nLeading semiconductor companies worldwide 2024, by market cap\nHardware\nSemiconductor companies market revenue share worldwide 2008-2023\nHardware\nSemiconductor market revenue growth worldwide 1988-2024\nTo download this statistic in XLS format you need a Statista Account\nTo download this statistic in PNG format you need a Statista Account\nTo download this statistic in PDF format you need a Statista Account\nTo download this statistic in PPT format you need a Statista Account\nAs a Premium user you get access to the detailed source references and background information about this statistic.\n Nvidia number of employees 2023, by region\nNvidia number of employees in 2023, by region\nAdditional Information\nShow sources information\nShow publisher information\nUse Ask Statista Research Service\nJuly 2023\nWorldwide\n2023\nIncludes full-time and part-time employees.\n Statistics on\n"\nNvidia\n"\nOther statistics that may interest you Nvidia\nOverview\nFinancials\nSegments\nESG\nCompetitors\nFurther Content: You might find this interesting as well\nTopics Transforming data into design:\nStatista Content & Design\nStrategy and business building for the data-driven economy:\nIndustry-specific and extensively researched technical data (partially from exclusive partnerships).'}, {'url': 'https://finance.yahoo.com/news/nvidia-announces-financial-results-fourth-212000202.html', 'content': "Proceeds related to employee stock plans\n-\n5\n403\n355\nPayments related to repurchases of common stock\n(2,660\n)\n(1,212\n)\n(9,533\n)\n(10,039\n)\nPayments related to tax on restricted stock units\n(841\n)\n(344\n)\n(2,783\n)\n(1,475\n)\nRepayment of debt\n-\n-\n(1,250\n)\n-\nDividends paid\n(99\n)\n(98\n)\n(395\n)\n(398\n)\nPrincipal payments on property and equipment and intangible assets\n(29\n)\n(4\n)\n(74\n)\n(58\n)\nOther\n-\n(3\n)\n(1\n)\n(2\n)\nNet cash used in financing activities\n(3,629\n)\n(1,656\n)\n(13,633\n)\n(11,617\n)\nChange in cash and cash equivalents\n1,761\n589\n3,891\n1,399\nCash and cash equivalents at beginning of period\n5,519\n2,800\n3,389\n1,990\nCash and cash equivalents at end of period\n$\n7,280\n$\n3,389\n$\n7,280\n$\n3,389\nSupplemental disclosures of cash flow information:\nCash paid for income taxes, net\n$\n1,874\n$\n32\n$\n6,549\n$\n1,404\nCash paid for interest\n$\n26\n$\n28\n$\n252\n$\n254\nNVIDIA CORPORATION\nRECONCILIATION OF GAAP TO NON-GAAP FINANCIAL MEASURES\n(In millions, except per share data)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nOctober 29,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2023\n2024\n2023\nGAAP gross profit\n$\n16,791\n$\n13,400\n$\n3,833\n$\n44,301\n$\n15,356\nGAAP gross margin\n76.0\n%\n74.0\n%\n63.3\n%\n72.7\n%\n56.9\n%\nAcquisition-related and other costs (A)\n119\n119\n120\n477\n455\nStock-based compensation expense (B)\n45\n38\n30\n141\n138\nIP-related costs\n4\n26\n16\n40\n16\nNon-GAAP gross profit\n$\n16,959\n$\n13,583\n$\n3,999\n$\n44,959\n$\n15,965\nNon-GAAP gross margin\n76.7\n%\n75.0\n%\n66.1\n%\n73.8\n%\n59.2\n%\nGAAP operating expenses\n$\n3,176\n$\n2,983\n$\n2,576\n$\n11,329\n$\n11,132\nStock-based compensation expense (B)\n(948\n)\n(941\n)\n(709\n)\n(3,408\n)\n(2,572\n)\nAcquisition-related and other costs (A)\n(18\n)\n(16\n)\n(54\n)\n(106\n)\n(219\n)\nAcquisition termination cost\n-\n-\n-\n-\n(1,353\n)\nOther (C)\n-\n-\n(38\n)\n10\n(63\n)\nNon-GAAP operating expenses\n$\n2,210\n$\n2,026\n$\n1,775\n$\n7,825\n$\n6,925\nGAAP operating income\n$\n13,615\n$\n10,417\n$\n1,257\n$\n32,972\n$\n4,224\nTotal impact of non-GAAP adjustments to operating income\n1,134\n1,140\n967\n4,162\n4,816\nNon-GAAP operating income\n$\n14,749\n$\n11,557\n$\n2,224\n$\n37,134\n$\n9,040\nGAAP other income (expense), net\n$\n491\n$\n105\n$\n32\n$\n846\n$\n(43\n)\n(Gains) losses from non-affiliated investments\n(260\n)\n69\n10\n(238\n)\n45\nInterest expense related to amortization of debt discount\n1\n1\n1\n4\n5\nNon-GAAP other income (expense), net\n$\n232\n$\n175\n$\n43\n$\n612\n$\n7\nGAAP net income\n$\n12,285\n$\n9,243\n$\n1,414\n$\n29,760\n$\n4,368\nTotal pre-tax impact of non-GAAP adjustments\n875\n1,210\n978\n3,928\n4,865\nIncome tax impact of non-GAAP adjustments (D)\n(321\n)\n(433\n)\n(218\n)\n(1,376\n)\n(867\n)\n Other, net\n260\n(18\n)\n237\n(48\n)\nOther income (expense), net\n491\n32\n846\n(43\n)\nIncome before income tax\n14,106\n1,289\n33,818\n4,181\nIncome tax expense (benefit)\n1,821\n(125\n)\n4,058\n(187\n)\nNet income\n$\n12,285\n$\n1,414\n$\n29,760\n$\n4,368\nNet income per share:\nBasic\n$\n4.98\n$\n0.57\n$\n12.05\n$\n1.76\nDiluted\n$\n4.93\n$\n0.57\n$\n11.93\n$\n1.74\nWeighted average shares used in per share computation:\nBasic\n2,466\n2,464\n2,469\n2,487\nDiluted\n2,490\n2,477\n2,494\n2,507\nNVIDIA CORPORATION\nCONDENSED CONSOLIDATED BALANCE SHEETS\n(In millions)\n(Unaudited)\nJanuary 28,\nJanuary 29,\n2024\n2023\nASSETS\nCurrent assets:\nCash, cash equivalents and marketable securities\n$\n25,984\n$\n13,296\nAccounts receivable, net\n9,999\n3,827\nInventories\n5,282\n5,159\nPrepaid expenses and other current assets\n3,080\n791\nTotal current assets\n44,345\n23,073\nProperty and equipment, net\n3,914\n3,807\nOperating lease assets\n1,346\n1,038\nGoodwill\n4,430\n4,372\nIntangible assets, net\n1,112\n1,676\nDeferred income tax assets\n6,081\n3,396\nOther assets\n4,500\n3,820\nTotal assets\n$\n65,728\n$\n41,182\nLIABILITIES AND SHAREHOLDERS' EQUITY\nCurrent liabilities:\nAccounts payable\n$\n2,699\n$\n1,193\nAccrued and other current liabilities\n6,682\n4,120\nShort-term debt\n1,250\n1,250\nTotal current liabilities\n10,631\n6,563\nLong-term debt\n8,459\n9,703\nLong-term operating lease liabilities\n1,119\n902\nOther long-term liabilities\n2,541\n1,913\nTotal liabilities\n22,750\n19,081\nShareholders' equity\n42,978\n22,101\nTotal liabilities and shareholders' equity\n$\n65,728\n$\n41,182\nNVIDIA CORPORATION\nCONDENSED CONSOLIDATED STATEMENTS OF CASH FLOWS\n(In millions)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2024\n2023\nCash flows from operating activities:\nNet income\n$\n12,285\n$\n1,414\n$\n29,760\n$\n4,368\nAdjustments to reconcile net income to net cash\nprovided by operating activities:\nStock-based compensation expense\n993\n738\n3,549\n2,709\nDepreciation and amortization\n387\n426\n1,508\n1,544\nDeferred income taxes\n(78\n)\n(647\n)\n(2,489\n)\n(2,164\n)\n(Gains) losses on investments in non-affiliated entities, net\n(260\n)\n10\n(238\n)\n45\nAcquisition termination cost\n-\n-\n-\n1,353\nOther\n(109\n)\n20\n(278\n)\n(7\n)\nChanges in operating assets and liabilities, net of acquisitions:\n Q4 Fiscal 2024 Summary\nGAAP\n($ in millions, except earnings per share)\nQ4 FY24\nQ3 FY24\nQ4 FY23\nQ/Q\nY/Y\nRevenue\n$22,103\n$18,120\n$6,051\nUp 22%\nUp 265%\nGross margin\n76.0%\n74.0%\n63.3%\nUp 2.0 pts\nUp 12.7 pts\nOperating expenses\n$3,176\n$2,983\n$2,576\nUp 6%\nUp 23%\nOperating income\n$13,615\n$10,417\n$1,257\nUp 31%\nUp 983%\nNet income\n$12,285\n$9,243\n$1,414\nUp 33%\nUp 769%\nDiluted earnings per share\n$4.93\n$3.71\n$0.57\nUp 33%\nUp 765%\nNon-GAAP\n($ in millions, except earnings per share)\nQ4 FY24\nQ3 FY24\nQ4 FY23\nQ/Q\nY/Y\nRevenue\n$22,103\n$18,120\n$6,051\nUp 22%\nUp 265%\nGross margin\n76.7%\n75.0%\n66.1%\nUp 1.7 pts\nUp 10.6 pts\nOperating expenses\n$2,210\n$2,026\n$1,775\nUp 9%\nUp 25%\nOperating income\n$14,749\n$11,557\n$2,224\nUp 28%\nUp 563%\nNet income\n$12,839\n$10,020\n$2,174\nUp 28%\nUp 491%\nDiluted earnings per share\n$5.16\n$4.02\n$0.88\nUp 28%\nUp 486%\nFiscal 2024 Summary\nGAAP\n($ in millions, except earnings per share)\n 2024\n2023\n2023\n2024\n2023\nCost of revenue\n$\n119\n$\n119\n$\n120\n$\n477\n$\n455\nResearch and development\n$\n12\n$\n12\n$\n10\n$\n49\n$\n39\nSales, general and administrative\n$\n6\n$\n4\n$\n44\n$\n57\n$\n180\n(B) Stock-based compensation consists of the following:\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nOctober 29,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2023\n2024\n2023\nCost of revenue\n$\n45\n$\n38\n$\n30\n$\n141\n$\n138\nResearch and development\n$\n706\n$\n701\n$\n527\n$\n2,532\n$\n1,892\nSales, general and administrative\n NVIDIA CORPORATION\nCONDENSED CONSOLIDATED STATEMENTS OF INCOME\n(In millions, except per share data)\n(Unaudited)\nThree Months Ended\nTwelve Months Ended\nJanuary 28,\nJanuary 29,\nJanuary 28,\nJanuary 29,\n2024\n2023\n2024\n2023\nRevenue\n$\n22,103\n$\n6,051\n$\n60,922\n$\n26,974\nCost of revenue\n5,312\n2,218\n16,621\n11,618\nGross profit\n16,791\n3,833\n44,301\n15,356\nOperating expenses\nResearch and development\n2,465\n1,951\n8,675\n7,339\nSales, general and administrative\n711\n625\n2,654\n2,440\nAcquisition termination cost\n-\n-\n-\n1,353\nTotal operating expenses\n3,176\n2,576\n11,329\n11,132\nOperating Income\n13,615\n1,257\n32,972\n4,224\nInterest income\n294\n115\n866\n267\nInterest expense\n(63\n)\n(65\n)\n(257\n)\n(262\n)\n"}, {'url': 'https://stockanalysis.com/stocks/nvda/employees/', 'content': 'NVIDIA had 29,600 employees on January 28, 2024. The number of employees increased by 3,404 or 12.99% compared to the previous year. Employees 29,600. Change (1Y) 3,404. ... Real-time quotes provided by IEX Cloud. Other market data may be delayed by 15 minutes or more. ...'}, {'url': 'https://investor.nvidia.com/news/press-release-details/2024/NVIDIA-Announces-Financial-Results-for-Fourth-Quarter-and-Fiscal-2024/?ref=robotradingnet.ghost.io', 'content': 'SANTA CLARA, Calif., Feb. 21, 2024 (GLOBE NEWSWIRE) -- NVIDIA (NASDAQ: NVDA) today reported revenue for the fourth quarter ended January 28, 2024, of $22.1 billion, up 22% from the previous quarter and up 265% from a year ago. For the quarter, GAAP earnings per diluted share was $4.93, up 33% from the previous quarter and up 765% from a year ...'}][0m[32;1m[1;3m
+ I have found the following data on the number of full-time employees at each company:
+ Microsoft: 221,000
+ Apple: 161,000
+ NVIDIA: 29,600
+ Now, I will write and execute Python code to plot this data.
+ {'tool_name': 'python_interpreter', 'parameters': {'code': 'import matplotlib.pyplot as plt\n\n# Data on the number of full-time employees at each company\ncompanies = [\n "Microsoft", "Apple", "NVIDIA"\n]\nfull_time_employees = [221000, 161000, 29600]\n\n# Plot the data\nplt.bar(companies, full_time_employees)\nplt.xlabel("Company")\nplt.ylabel("Number of Full Time Employees")\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.savefig("tech_companies_market_cap_employees.png")'}}
+ [0m[33;1m[1;3m[0m[32;1m[1;3mRelevant Documents: 0,1,3,4,5,7,8,9,10,11,12,15,18,20
+ Cited Documents: 1,3,4,7,8,10,11,15,18,20
+ Answer: Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:
+
+
+ The companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.
+ Grounded answer: Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:
+ ! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')
+
+ The companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ {'input': 'Create a plot of the number of full time employees at the 3 tech companies with the highest market cap in the United States in 2024.',
+ 'output': "Here is a plot showing the number of full-time employees at the three US tech companies with the highest market cap in 2024:\n! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')\n\nThe companies with the highest number of full-time employees are Microsoft with 221,000, Apple with 161,000 and NVIDIA with 29,600.",
+ 'citations': [CohereCitation(start=125, end=201, text="! [Number of Full Time Employees]('tech_companies_market_cap_employees.png')", documents=[{'output': ''}]),
+ CohereCitation(start=268, end=277, text='Microsoft', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
+ CohereCitation(start=283, end=290, text='221,000', documents=[{'url': 'https://www.microsoft.com/investor/reports/ar23/index.html', 'content': 'As of June 30, 2023, we employed approximately 221,000 people on a full-time basis, 120,000 in the U.S. and 101,000 internationally. Of the total employed people, 89,000 were in operations, including manufacturing, distribution, product support, and consulting services; 72,000 were in product research and development; 45,000 were in sales and ...'}, {'url': 'https://www.macrotrends.net/stocks/charts/MSFT/microsoft/number-of-employees', 'content': 'Interactive chart of Microsoft (MSFT) annual worldwide employee count from 2010 to 2023. Microsoft total number of employees in 2023 was 221,000, a 0% decline from 2022. Microsoft total number of employees in 2022 was 221,000, a 22.1% increase from 2021. Microsoft total number of employees in 2021 was 181,000, a 11.04% increase from 2020.'}]),
+ CohereCitation(start=292, end=297, text='Apple', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://www.forbes.com/advisor/investing/best-tech-stocks/', 'content': 'eToro\nThe Best Tech Stocks of November 2023\nApple Inc. (AAPL)\n$2.8 trillion\n0.5%\n27.1%\n$2.8 trillion\n0.5%\n27.1%\nApple\xa0 was founded in Los Altos, Calif., by Steve Jobs and Steve Wozniak in 1976. ASML Holding NV (ASML)\n$248 billion\n1.0%\n22.8%\n$248 billion\n1.0%\n22.8%\nASML is a Netherlands-based company that designs and manufactures the machinery used by companies that make microchips. Taiwan Semiconductor Manufacturing Company (TSM)\n$443 billion\n2.0%\n20.6%\n$443 billion\n2.0%\n20.6%\nTaiwan Semiconductor Manufacturing Company could be the biggest tech company you’ve never heard of. NVIDIA Corp (NVDA)\n$1.1 trillion\n0.0%\n62.8%\n$1.1 trillion\n0.0%\n62.8%\nNVIDIA was founded in 1993 to produce graphic cards for the burgeoning personal computer market. Microsoft Corporation (MSFT)\n$2.6 trillion\n0.8%\n27.3%\n$2.6 trillion\n0.8%\n27.3%\nMicrosoft\xa0 was founded in 1975 by Bill Gates and Paul Allen in Albuquerque, N.M.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
+ CohereCitation(start=303, end=310, text='161,000', documents=[{'url': 'https://www.macrotrends.net/stocks/charts/AAPL/apple/number-of-employees', 'content': 'Employee Count. Interactive chart of Apple (AAPL) annual worldwide employee count from 2010 to 2023. Apple total number of employees in 2023 was 161,000, a 1.83% decline from 2022. Apple total number of employees in 2022 was 164,000, a 6.49% increase from 2021. Apple total number of employees in 2021 was 154,000, a 4.76% increase from 2020.'}, {'url': 'https://www.businessinsider.com/apple-layoffs-tim-cook-getting-serious-challenges-car-china-iphone-2024-4?op=1', 'content': "2024-04-05T12:27:33Z An curved arrow pointing right. Share. The ... That's especially so when considering that Apple had about 161,000 full-time employees at the end of its last fiscal year."}]),
+ CohereCitation(start=315, end=321, text='NVIDIA', documents=[{'url': 'https://www.financecharts.com/screener/biggest-country-us', 'content': 'Biggest Companies in the US by Market Cap for Apr 2024. The most valuable company in the US is Microsoft (MSFT) with a market cap of $3.159T, followed by Apple (AAPL) and NVIDIA (NVDA). Last updated Apr 05, 2024.'}, {'url': 'https://disfold.com/united-states/sector/technology/companies/', 'content': 'Unlock Financial AI:\nStart your Free Trial of\nDisfold AI, Now!\nTop Technology Companies from the United States as of Jan. 01, 2024\n(Dec. 1, 2023)\nTop Technology Companies from the United States as of Jan. 01, 2024\n1.\nApple\nMarket Cap (USD):\n$2.866 T\nStock:\nAAPL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nConsumer Electronics\n2.\nMicrosoft\nMarket Cap (USD):\n$2.755 T\nStock:\nMSFT\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n3.\nNvidia\nMarket Cap (USD):\n$1.186 T\nStock:\nNVDA\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n4.\nBroadcom\nMarket Cap (USD):\n$495.95 B\nStock:\nAVGO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n5.\nOracle\nMarket Cap (USD):\n$282.01 B\nStock:\nORCL\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n6.\n Marvell Technology, Inc.\nMarket Cap (USD):\n$49.61 B\nStock:\n9MW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n35.\nAutodesk, Inc.\nMarket Cap (USD):\n$48.97 B\nStock:\nADSK\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n36.\nMicrochip Technology Incorporated\nMarket Cap (USD):\n$45.77 B\nStock:\nMCHP\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n37.\nFortinet, Inc.\nMarket Cap (USD):\n$44.84 B\nStock:\n Analog Devices\nMarket Cap (USD):\n$93.79 B\nStock:\nADI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n20.\nMicron Technology, Inc.\nMarket Cap (USD):\n$91.30 B\nStock:\nMU\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n21.\nPalo Alto Networks\nMarket Cap (USD):\n$90.41 B\nStock:\nPANW\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n22.\n Fiserv\nMarket Cap (USD):\n$79.73 B\nStock:\nFI\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nInformation Technology Services\n23.\nKLA\nMarket Cap (USD):\n$75.13 B\nStock:\nKLAC\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductor Equipment & Materials\n24.\nSynopsys\nMarket Cap (USD):\n$74.64 B\nStock:\nSNPS\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Infrastructure\n25.\n Salesforce\nMarket Cap (USD):\n$243.78 B\nStock:\nCRM\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSoftware—Application\n8.\nAMD\nMarket Cap (USD):\n$219.72 B\nStock:\nAMD\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nSemiconductors\n9.\nCisco\nMarket Cap (USD):\n$205.21 B\nStock:\nCSCO\nwb_incandescent\nCountry:\nUnited States\nSector:\nTechnology\nIndustry:\nCommunication Equipment\n10.\n'}]),
+ CohereCitation(start=327, end=333, text='29,600', documents=[{'url': 'https://stockanalysis.com/stocks/nvda/employees/', 'content': 'NVIDIA had 29,600 employees on January 28, 2024. The number of employees increased by 3,404 or 12.99% compared to the previous year. Employees 29,600. Change (1Y) 3,404. ... Real-time quotes provided by IEX Cloud. Other market data may be delayed by 15 minutes or more. ...'}, {'url': 'https://www.macrotrends.net/stocks/charts/NVDA/nvidia/number-of-employees', 'content': 'Employee Count. Interactive chart of NVIDIA (NVDA) annual worldwide employee count from 2010 to 2024. NVIDIA total number of employees in 2024 was 29,600, a 12.99% increase from 2023. NVIDIA total number of employees in 2023 was 26,196, a 16.57% increase from 2022. NVIDIA total number of employees in 2022 was 22,473, a 18.43% increase from 2021.'}])]}
+
+
+
+
+
+
+
+
+
+
+```python
+# notice that the model did websearch calls, then used python to do some analysis
+# the model can even self-debug itself if the python code was wrong
```
-
+# Let's ask another question to the data analyst -- which requires a direct answer
+
-```python PYTHON
+```python
agent_executor.invoke({
"input": "Hey how are you?",
})
```
-````txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3mPlan: I will respond to the user's greeting.
-Action: ```json JSON
-[
- {
- "tool_name": "directly_answer",
- "parameters": {}
- }
-]
-```
-Relevant Documents: None
-Cited Documents: None
-Answer: Hey, I'm doing well, thank you for asking! How can I help you today?
-Grounded answer: Hey, I'm doing well, thank you for asking! How can I help you today?[0m
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3mPlan: I will respond to the user's greeting.
+ Action: ```json
+ [
+ {
+ "tool_name": "directly_answer",
+ "parameters": {}
+ }
+ ]
+ ```
+ Relevant Documents: None
+ Cited Documents: None
+ Answer: Hey, I'm doing well, thank you for asking! How can I help you today?
+ Grounded answer: Hey, I'm doing well, thank you for asking! How can I help you today?[0m
+
+ [1m> Finished chain.[0m
+
+
-[1m> Finished chain.[0m
+ {'input': 'Hey how are you?',
+ 'output': "Hey, I'm doing well, thank you for asking! How can I help you today?",
+ 'citations': []}
-{'input': 'Hey how are you?',
- 'output': "Hey, I'm doing well, thank you for asking! How can I help you today?",
- 'citations': []}
-````
+This is a simple example to get you start. There [are many tools](https://python.langchain.com/docs/integrations/tools/) you can equip your agent with. Once youre comfortable with these ideas, you can also proceed to define your tools (see [Multi-step tool use in Action](https://docs.cohere.com/docs/multi-step-tool-use#multi-step-tool-use-in-action)).
-This is a simple example to get you started. There [are many tools](https://python.langchain.com/docs/integrations/tools/) you can equip your agent with. Once you're comfortable with these ideas, you can also proceed to define your tools (see [Multi-step tool use in Action](https://docs.cohere.com/docs/multi-step-tool-use#multi-step-tool-use-in-action)).
diff --git a/fern/pages/cookbooks/document-parsing-for-enterprises.mdx b/fern/pages/cookbooks/document-parsing-for-enterprises.mdx
index b3f22f0f6..f095676e8 100644
--- a/fern/pages/cookbooks/document-parsing-for-enterprises.mdx
+++ b/fern/pages/cookbooks/document-parsing-for-enterprises.mdx
@@ -3,7 +3,7 @@ title: Advanced Document Parsing For Enterprises
slug: /page/document-parsing-for-enterprises
description: "This page describes how to use Cohere's models to build a document-parsing agent."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, AI agents, document parsing"
---
@@ -14,30 +14,36 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Giannis Chatziveroglou",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/73153cb-giannis.jpeg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/73153cb-giannis.jpeg"
+ },
+ {
+ name: "Justin Lee",
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/3678fac-Justin.jpg"
+ }
]}
/>
-
+
+
+
## Introduction
The bread and butter of natural language processing technology is text. Once we can reduce a set of data into text, we can do all kinds of things with it: question answering, summarization, classification, sentiment analysis, searching and indexing, and more.
-
+
+
In the context of enterprise Retrieval Augmented Generation (RAG), the information is often locked in complex file types such as PDFs. These formats are made for sharing information between humans, but not so much with language models.
+
+
+In this notebook, we will use a real-world pharmaceutical drug label to test out various performant approaches to parsing PDFs. This will allow us to use [Cohere's Command-R model](https://txt.cohere.com/command-r/) in a RAG setting to answer questions and asks about this label, such as "I need a succinct summary of the compound name, indication, route of administration, and mechanism of action of" a given pharmaceutical.
+
+
+
-In this notebook, we will use a real-world pharmaceutical drug label to test out various performant approaches to parsing PDFs. This will allow us to use [Cohere's Command-R model](https://cohere.com/blog/command-r/) in a RAG setting to answer questions and asks about this label, such as "I need a succinct summary of the compound name, indication, route of administration, and mechanism of action of" a given pharmaceutical.
-
-
-
-## PDF Parsing [#top]
+
+## PDF Parsing
We will go over five proprietary as well as open source options for processing PDFs. The parsing mechanisms demonstrated in the following sections are
-
- [Google Document AI](#gcp)
- [AWS Textract](#aws)
- [Unstructured.io](#unstructured)
@@ -46,35 +52,34 @@ We will go over five proprietary as well as open source options for processing P
By way of example, we will be parsing a [21-page PDF](https://www.accessdata.fda.gov/drugsatfda_docs/label/2023/215500s000lbl.pdf) containing the label for a recent FDA drug approval, the beginning of which is shown below. Then, we will perform a series of basic RAG tasks with our different parsings and evaluate their performance.
-
+
## Getting Set Up
Before we dive into the technical weeds, we need to set up the notebook's runtime and filesystem environments. The code cells below do the following:
-
- Install required libraries
- Confirm that data dependencies from the GitHub repo have been downloaded. These will be under `data/document-parsing` and contain the following:
- - the PDF document that we will be working with, `fda-approved-drug.pdf` (this can also be found here: https://www.accessdata.fda.gov/drugsatfda_docs/label/2023/215500s000lbl.pdf)
- - precomputed parsed documents for each parsing solution. While the point of this notebook is to illustrate how this is done, we provide the parsed final results to allow readers to skip ahead to the RAG section without having to set up the required infrastructure for each solution.)
+ - the PDF document that we will be working with, `fda-approved-drug.pdf` (this can also be found here: https://www.accessdata.fda.gov/drugsatfda_docs/label/2023/215500s000lbl.pdf)
+ - precomputed parsed documents for each parsing solution. While the point of this notebook is to illustrate how this is done, we provide the parsed final results to allow readers to skip ahead to the RAG section without having to set up the required infrastructure for each solution.)
- Add utility functions needed for later sections
-```python PYTHON
+
+```python
%%capture
! sudo apt install tesseract-ocr poppler-utils
! pip install "cohere<5" fsspec hnswlib google-cloud-documentai google-cloud-storage boto3 langchain-text-splitters llama_parse pytesseract pdf2image pandas
```
-```python PYTHON
+
+```python
data_dir = "data/document-parsing"
source_filename = "example-drug-label"
extension = "pdf"
```
-```python PYTHON
+
+```python
from pathlib import Path
sources = ["gcp", "aws", "unstructured-io", "llamaparse-text", "llamaparse-markdown", "pytesseract"]
@@ -82,23 +87,24 @@ sources = ["gcp", "aws", "unstructured-io", "llamaparse-text", "llamaparse-markd
filenames = ["{}-parsed-fda-approved-drug.txt".format(source) for source in sources]
filenames.append("fda-approved-drug.pdf")
-for filename in filenames:
+for filename in filenames:
file_path = Path(f"{data_dir}/{filename}")
if file_path.is_file() == False:
print(f"File {filename} not found at {data_dir}!")
```
### Utility Functions
-
Make sure to include the notebook's utility functions in the runtime.
-```python PYTHON
+
+```python
def store_document(path: str, doc_content: str):
with open(path, 'w') as f:
f.write(doc_content)
```
-```python PYTHON
+
+```python
import json
def insert_citations_in_order(text, citations, documents):
@@ -134,7 +140,8 @@ def insert_citations_in_order(text, citations, documents):
return text_with_citations, "\n".join(citations_reference)
```
-```python PYTHON
+
+```python
def format_docs_for_chat(documents):
return [{"id": str(index), "text": x} for index, x in enumerate(documents)]
```
@@ -143,25 +150,26 @@ def format_docs_for_chat(documents):
For demonstration purposes, we have collected and saved the parsed documents from each solution in this notebook. Skip to the [next section](#document-questions) to run RAG with Command-R on the pre-fetched versions. You can find all parsed resources in detail at the link [here](https://github.com/gchatz22/temp-cohere-resources/tree/main/data).
-### Solution 1: Google Cloud Document AI [[Back to Solutions]](#top) [#gcp]
+
+### Solution 1: Google Cloud Document AI [[Back to Solutions]](#top)
Document AI helps developers create high-accuracy processors to extract, classify, and split documents.
-
+
External documentation: https://cloud.google.com/document-ai
#### Parsing the document
-The following block can be executed in one of two ways:
-
-- Inside a Google Vertex AI environment
- - No authentication needed
-- From this notebook
- - Authentication is needed
- - There are pointers inside the code on which lines to uncomment in order to make this work
-
+The following block can be executed in one of two ways
+1. Inside a Google Vertex AI environment
+ - No authentication is needed
+2. Inside the notebook
+ - Authentication needed
+ - There are pointers inside the code on which lines to uncomment in order to achieve that
+
**Note: You can skip to the next block if you want to use the pre-existing parsed version.**
-```python PYTHON
+
+```python
"""
Extracted from https://cloud.google.com/document-ai/docs/samples/documentai-batch-process-document
"""
@@ -273,39 +281,46 @@ def batch_process_documents(
# )
```
-```python PYTHON
+
+```python
"""
Post process parsed document and store it locally.
-Make sure to run this in a Google Vertex AI environment or include a credentials file.
+Make sure to run in Google Vertex AI environment or include a credentials file.
"""
-"""
-from pathlib import Path
-from collections import defaultdict
+# from pathlib import Path
+# from collections import defaultdict
-parsed_documents = []
-combined_versioned_parsed_documents = defaultdict(list)
-
-# Assemble versioned documents together ({"doc_name": [(0, doc_content_0), (1, doc_content_1), ...]}).
-for filename, doc_content in versioned_parsed_documents:
- filename, version = "-".join(filename.split("-")[:-1]), filename.split("-")[-1]
- combined_versioned_parsed_documents[filename].append((version, doc_content))
-
-# Sort documents by version and join the content together.
-for filename, docs in combined_versioned_parsed_documents.items():
- doc_content = " ".join([x[1] for x in sorted(docs, key=lambda x: x[0])])
- parsed_documents.append((filename, doc_content))
-
-# Store parsed documents in local storage.
-for filename, doc_content in parsed_documents:
- file_path = "{}/{}-parsed-{}.txt".format(data_dir, "gcp", source_filename)
- store_document(file_path, doc_content)
-"""
+# parsed_documents = []
+# combined_versioned_parsed_documents = defaultdict(list)
+
+# # Assemble versioned documents together ({"doc_name": [(0, doc_content_0), (1, doc_content_1), ...]}).
+# for filename, doc_content in versioned_parsed_documents:
+# filename, version = "-".join(filename.split("-")[:-1]), filename.split("-")[-1]
+# combined_versioned_parsed_documents[filename].append((version, doc_content))
+
+# # Sort documents by version and join the content together.
+# for filename, docs in combined_versioned_parsed_documents.items():
+# doc_content = " ".join([x[1] for x in sorted(docs, key=lambda x: x[0])])
+# parsed_documents.append((filename, doc_content))
+
+# # Store parsed documents in local storage.
+# for filename, doc_content in parsed_documents:
+# file_path = "{}/{}-parsed-{}.txt".format(data_dir, "gcp", source_filename)
+# store_document(file_path, doc_content)
```
+
+
+
+ '\nPost process parsed document and store it locally.\nMake sure to run in Google Vertex AI environment or include a credentials file.\n'
+
+
+
#### Visualize the parsed document
-```python PYTHON
+
+```python
filename = "gcp-parsed-{}.txt".format(source_filename)
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
@@ -313,13 +328,16 @@ with open("{}/{}".format(data_dir, filename), "r") as doc:
print(parsed_document[:1000])
```
-### Solution 2: AWS Textract [[Back to Solutions]](#top) [#aws]
+
+### Solution 2: AWS Textract [[Back to Solutions]](#top)
[Amazon Textract](https://aws.amazon.com/textract/) is an OCR service offered by AWS. It can detect text, forms, tables, and more in PDFs and images. In this section, we go over how to use Textract's asynchronous API.
+
+
#### Parsing the document
-We assume that you are working within the AWS ecosystem (from a SageMaker notebook, EC2 instance, a Lambda function, etc.) with valid credentials. Much of the code here is from supplemental materials created by AWS and offered here:
+We assume you are working within the AWS ecosystem (from a SageMaker notebook, EC2 instance, a Lambda function, ...) with valid credentials. Much of the code here is from supplemental materials created by AWS and offered here:
- https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/textract
- https://github.com/aws-samples/textract-paragraph-identification/tree/main
@@ -333,7 +351,8 @@ At minimum, you will need access to the following AWS resources to get started:
First, we bring in the `TextractWrapper` class provided in the [AWS Code Examples repository](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/python/example_code/textract/textract_wrapper.py). This class makes it simpler to interface with the Textract service.
-```python PYTHON
+
+```python
# source: https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/textract
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ -616,7 +635,10 @@ class TextractWrapper:
Next, we set up Textract and S3, and provide this to an instance of `TextractWrapper`.
-```python PYTHON
+
+
+
+```python
import boto3
textract_client = boto3.client('textract')
@@ -634,7 +656,8 @@ Asynchronous calls follow the below process:
3. Once the request is complete, Textract sends out a message to the SNS topic. This can be used in conjunction with other services such as Lambda or SQS for downstream processes.
4. The parsed results can be fetched from Textract in chunks via the job ID.
-```python PYTHON
+
+```python
bucket_name = "your-bucket-name"
sns_topic_arn = "your-sns-arn" # this can be found under the topic you created in the Amazon SNS dashboard
sns_role_arn = "sns-role-arn" # this is an IAM role that allows Textract to interact with SNS
@@ -642,7 +665,8 @@ sns_role_arn = "sns-role-arn" # this is an IAM role that allows Textract to inte
file_name = "example-drug-label.pdf"
```
-```python PYTHON
+
+```python
# kick off a text detection job. This returns a job ID.
job_id = textractWrapper.start_detection_job(bucket_name=bucket_name, document_file_name=file_name,
sns_topic_arn=sns_topic_arn, sns_role_arn=sns_role_arn)
@@ -650,13 +674,14 @@ job_id = textractWrapper.start_detection_job(bucket_name=bucket_name, document_f
Once the job completes, this will return a dictionary with the following keys:
-`dict_keys(['DocumentMetadata', 'JobStatus', 'NextToken', 'Blocks', 'AnalyzeDocumentModelVersion', 'ResponseMetadata'])`
+```dict_keys(['DocumentMetadata', 'JobStatus', 'NextToken', 'Blocks', 'AnalyzeDocumentModelVersion', 'ResponseMetadata'])```
This response corresponds to one chunk of information parsed by Textract. The number of chunks a document is parsed into depends on the length of the document. The two keys we are most interested in are `Blocks` and `NextToken`. `Blocks` contains all of the information that was extracted from this chunk, while `NextToken` tells us what chunk comes next, if any.
Textract returns an information-rich representation of the extracted text, such as their position on the page and hierarchical relationships with other entities, all the way down to the individual word level. Since we are only interested in the raw text, we need a way to parse through all of the chunks and their `Blocks`. Lucky for us, Amazon provides some [helper functions](https://github.com/aws-samples/textract-paragraph-identification/tree/main) for this purpose, which we utilize below.
-```python PYTHON
+
+```python
def get_text_results_from_textract(job_id):
response = textract_client.get_document_text_detection(JobId=job_id)
collection_of_textract_responses = []
@@ -733,7 +758,8 @@ We feed in the Job ID from before into the function `get_text_results_from_textr
Finally, we can concatenate the lines into one string to pass into our downstream RAG pipeline.
-```python PYTHON
+
+```python
all_text = "\n".join([line["text"] if line else "" for line in text_info_with_line_spacing])
with open(f"aws-parsed-{source_filename}.txt", "w") as f:
@@ -742,7 +768,8 @@ with open(f"aws-parsed-{source_filename}.txt", "w") as f:
#### Visualize the parsed document
-```python PYTHON
+
+```python
filename = "aws-parsed-{}.txt".format(source_filename)
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
@@ -750,22 +777,23 @@ with open("{}/{}".format(data_dir, filename), "r") as doc:
print(parsed_document[:1000])
```
-### Solution 3: Unstructured.io [[Back to Solutions]](#top) [#unstructured]
+
+### Solution 3: Unstructured.io [[Back to Solutions]](#top)
Unstructured.io provides libraries with open-source components for pre-processing text documents such as PDFs, HTML and Word Documents.
-
+
External documentation: https://github.com/Unstructured-IO/unstructured-api
#### Parsing the document
The guide assumes an endpoint exists that hosts this service. The API is offered in two forms
-
1. [a hosted version](https://unstructured.io/)
2. [an OSS docker image](https://github.com/Unstructured-IO/unstructured-api?tab=readme-ov-file#dizzy-instructions-for-using-the-docker-image)
-
+
**Note: You can skip to the next block if you want to use the pre-existing parsed version.**
-```python PYTHON
+
+```python
import os
import requests
@@ -793,7 +821,8 @@ parsed_document = " ".join([parsed_entry["text"] for parsed_entry in parsed_resp
print("Parsed {}".format(source_filename))
```
-```python PYTHON
+
+```python
"""
Post process parsed document and store it locally.
"""
@@ -804,7 +833,8 @@ store_document(file_path, parsed_document)
#### Visualize the parsed document
-```python PYTHON
+
+```python
filename = "unstructured-io-parsed-{}.txt".format(source_filename)
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
@@ -812,24 +842,27 @@ with open("{}/{}".format(data_dir, filename), "r") as doc:
print(parsed_document[:1000])
```
-### Solution 4: LlamaParse [[Back to Solutions]](#top) [#llama]
+
-LlamaParse is an API created by LlamaIndex to efficiently parse and represent files for efficient retrieval and context augmentation using LlamaIndex frameworks.
+### Solution 4: LlamaParse [[Back to Solutions]](#top)
+LlamaParse is an API created by LlamaIndex to efficiently parse and represent files for efficient retrieval and context augmentation using LlamaIndex frameworks.
+
External documentation: https://github.com/run-llama/llama_parse
#### Parsing the document
The following block uses the LlamaParse cloud offering. You can learn more and fetch a respective API key for the service [here](https://cloud.llamaindex.ai/parse).
-
+
Parsing documents with LlamaParse offers an option for two output modes both of which we will explore and compare below
-
- Text
- Markdown
+
**Note: You can skip to the next block if you want to use the pre-existing parsed version.**
-```python PYTHON
+
+```python
import os
from llama_parse import LlamaParse
@@ -840,7 +873,8 @@ llama_index_api_key = "{API_KEY}"
input_path = "{}/{}.{}".format(data_dir, source_filename, extension)
```
-```python PYTHON
+
+```python
# Text mode
text_parser = LlamaParse(
api_key=llama_index_api_key,
@@ -853,7 +887,8 @@ text_parsed_document = " ".join([parsed_entry.text for parsed_entry in text_resp
print("Parsed {} to text".format(source_filename))
```
-```python PYTHON
+
+```python
"""
Post process parsed document and store it locally.
"""
@@ -862,7 +897,8 @@ file_path = "{}/{}-text-parsed-fda-approved-drug.txt".format(data_dir, "llamapar
store_document(file_path, text_parsed_document)
```
-```python PYTHON
+
+```python
# Markdown mode
markdown_parser = LlamaParse(
api_key=llama_index_api_key,
@@ -875,7 +911,8 @@ markdown_parsed_document = " ".join([parsed_entry.text for parsed_entry in markd
print("Parsed {} to markdown".format(source_filename))
```
-```python PYTHON
+
+```python
"""
Post process parsed document and store it locally.
"""
@@ -886,45 +923,52 @@ store_document(file_path, markdown_parsed_document)
#### Visualize the parsed document
-```python PYTHON
+
+```python
# Text parsing
filename = "llamaparse-text-parsed-{}.txt".format(source_filename)
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
-
+
print(parsed_document[:1000])
```
-```python PYTHON
+
+```python
# Markdown parsing
filename = "llamaparse-markdown-parsed-fda-approved-drug.txt"
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
-
+
print(parsed_document[:1000])
```
-### Solution 5: pdf2image + pytesseract [[Back to Solutions]](#top) [#pdf2image]
+
+
+### Solution 5: pdf2image + pytesseract [[Back to Solutions]](#top)
The final parsing method we examine does not rely on cloud services, but rather relies on two libraries: `pdf2image`, and `pytesseract`. `pytesseract` lets you perform OCR locally on images, but not PDF files. So, we first convert our PDF into a set of images via `pdf2image`.
#### Parsing the document
-```python PYTHON
+
+```python
from matplotlib import pyplot as plt
from pdf2image import convert_from_path
import pytesseract
```
-```python PYTHON
+
+```python
# pdf2image extracts as a list of PIL.Image objects
pages = convert_from_path(filename)
```
-```python PYTHON
+
+```python
# we look at the first page as a sanity check:
plt.imshow(pages[0])
@@ -934,25 +978,27 @@ plt.show()
Now, we can process the image of each page with `pytesseract` and concatenate the results to get our parsed document.
-```python PYTHON
+
+```python
label_ocr_pytesseract = "".join([pytesseract.image_to_string(page) for page in pages])
```
-```python PYTHON
+
+```python
print(label_ocr_pytesseract[:200])
```
-```txt title="Output"
-HIGHLIGHTS OF PRESCRIBING INFORMATION
+ HIGHLIGHTS OF PRESCRIBING INFORMATION
+
+ These highlights do not include all the information needed to use
+ IWILFIN™ safely and effectively. See full prescribing information for
+ IWILFIN.
+
+ IWILFIN™ (eflor
-These highlights do not include all the information needed to use
-IWILFIN™ safely and effectively. See full prescribing information for
-IWILFIN.
-IWILFIN™ (eflor
-```
-```python PYTHON
+```python
label_ocr_pytesseract = "".join([pytesseract.image_to_string(page) for page in pages])
with open(f"pytesseract-parsed-{source_filename}.txt", "w") as f:
@@ -961,7 +1007,8 @@ with open(f"pytesseract-parsed-{source_filename}.txt", "w") as f:
#### Visualize the parsed document
-```python PYTHON
+
+```python
filename = "pytesseract-parsed-{}.txt".format(source_filename)
with open("{}/{}".format(data_dir, filename), "r") as doc:
parsed_document = doc.read()
@@ -969,10 +1016,10 @@ with open("{}/{}".format(data_dir, filename), "r") as doc:
print(parsed_document[:1000])
```
-## Document Questions [#document-questions]
+
+## Document Questions
We can now ask a set of simple + complex questions and see how each parsing solution performs with Command-R. The questions are
-
- **What are the most common adverse reactions of Iwilfin?**
- Task: Simple information extraction
- **What is the recommended dosage of IWILFIN on body surface area between 0.5 and 0.75?**
@@ -980,12 +1027,14 @@ We can now ask a set of simple + complex questions and see how each parsing solu
- **I need a succinct summary of the compound name, indication, route of administration, and mechanism of action of Iwilfin.**
- Task: Overall document summary
-```python PYTHON
+
+```python
import cohere
co = cohere.Client(api_key="{API_KEY}")
```
-```python PYTHON
+
+```python
"""
Document Questions
"""
@@ -1004,11 +1053,13 @@ source = "gcp"
# source = "pytesseract"
```
-## Data Ingestion [#ingestion]
+## Data Ingestion
+
In order to set up our RAG implementation, we need to separate the parsed text into chunks and load the chunks to an index. The index will allow us to retrieve relevant passages from the document for different queries. Here, we use a simple implementation of indexing using the `hnswlib` library. Note that there are many different indexing solutions that are appropriate for specific production use cases.
-```python PYTHON
+
+```python
"""
Read parsed document content and chunk data
"""
@@ -1042,14 +1093,16 @@ documents = [c.page_content for c in chunks_]
print("Source document has been broken down to {} chunks".format(len(documents)))
```
-```python PYTHON
+
+```python
"""
Embed document chunks
"""
document_embeddings = co.embed(texts=documents, model="embed-english-v3.0", input_type="search_document").embeddings
```
-```python PYTHON
+
+```python
"""
Create document index and add embedded chunks
"""
@@ -1062,15 +1115,15 @@ index.add_items(document_embeddings, list(range(len(document_embeddings))))
print("Count:", index.element_count)
```
-```txt title="Output"
-Count: 115
-```
+ Count: 115
+
## Retrieval
In this step, we use k-nearest neighbors to fetch the most relevant documents for our query. Once the nearest neighbors are retrieved, we use Cohere's reranker to reorder the documents in the most relevant order with regards to our input search query.
-```python PYTHON
+
+```python
"""
Embed search query
Fetch k nearest neighbors
@@ -1084,7 +1137,8 @@ neighbors = [(result[0][0][i], result[1][0][i]) for i in range(len(result[0][0])
relevant_docs = [documents[x[0]] for x in sorted(neighbors, key=lambda x: x[1])]
```
-```python PYTHON
+
+```python
"""
Rerank retrieved documents
"""
@@ -1095,7 +1149,8 @@ reranked_relevant_docs = format_docs_for_chat([x.document["text"] for x in reran
## Final Step: Call Command-R + RAG!
-```python PYTHON
+
+```python
"""
Call the /chat endpoint with command-r
"""
@@ -1117,12 +1172,14 @@ print(citations_reference)
Run the code cells below to make head to head comparisons of the different parsing techniques across different questions.
-```python PYTHON
+
+```python
import pandas as pd
results = pd.read_csv("{}/results-table.csv".format(data_dir))
```
-```python PYTHON
+
+```python
question = input("""
Question 1: What are the most common adverse reactions of Iwilfin?
Question 2: What is the recommended dosage of Iwilfin on body surface area between 0.5 m2 and 0.75 m2?
@@ -1145,85 +1202,87 @@ for src in ["gcp", "aws", "unstructured-io", "llamaparse-text", "llamaparse-mark
print("\n")
```
-```txt title="Output"
-Question 1: What are the most common adverse reactions of Iwilfin?
-Question 2: What is the recommended dosage of Iwilfin on body surface area between 0.5 m2 and 0.75 m2?
-Question 3: I need a succinct summary of the compound name, indication, route of administration, and mechanism of action of Iwilfin.
-
-Pick which question you want to see (1,2,3): 3
-Do you want to see the references as well? References are long and noisy (y/n): n
-
-
-
-| gcp |
-
-
-Compound Name: eflornithine hydrochloride ([0], [1], [2]) (IWILFIN ([1])™)
-
-Indication: used to reduce the risk of relapse in adult and paediatric patients with high-risk neuroblastoma (HRNB) ([1], [3]), who have responded at least partially to prior multiagent, multimodality therapy. ([1], [3], [4])
-
-Route of Administration: IWILFIN™ tablets ([1], [3], [4]) are taken orally twice daily ([3], [4]), with doses ranging from 192 to 768 mg based on body surface area. ([3], [4])
-
-Mechanism of Action: IWILFIN™ is an ornithine decarboxylase inhibitor. ([0], [2])
-
-
-
-| aws |
+
+ Question 1: What are the most common adverse reactions of Iwilfin?
+ Question 2: What is the recommended dosage of Iwilfin on body surface area between 0.5 m2 and 0.75 m2?
+ Question 3: I need a succinct summary of the compound name, indication, route of administration, and mechanism of action of Iwilfin.
+
+ Pick which question you want to see (1,2,3): 3
+ Do you want to see the references as well? References are long and noisy (y/n): n
+
+
+
+ | gcp |
+
+
+ Compound Name: eflornithine hydrochloride ([0], [1], [2]) (IWILFIN ([1])™)
+
+ Indication: used to reduce the risk of relapse in adult and paediatric patients with high-risk neuroblastoma (HRNB) ([1], [3]), who have responded at least partially to prior multiagent, multimodality therapy. ([1], [3], [4])
+
+ Route of Administration: IWILFIN™ tablets ([1], [3], [4]) are taken orally twice daily ([3], [4]), with doses ranging from 192 to 768 mg based on body surface area. ([3], [4])
+
+ Mechanism of Action: IWILFIN™ is an ornithine decarboxylase inhibitor. ([0], [2])
+
+
+
+ | aws |
+
+
+ Compound Name: eflornithine ([0], [1], [2], [3]) (IWILFIN ([0])™)
+
+ Indication: used to reduce the risk of relapse ([0], [3]) in adults ([0], [3]) and paediatric patients ([0], [3]) with high-risk neuroblastoma (HRNB) ([0], [3]) who have responded to prior therapies. ([0], [3], [4])
+
+ Route of Administration: Oral ([2], [4])
+
+ Mechanism of Action: IWILFIN is an ornithine decarboxylase inhibitor. ([1])
+
+
+ | unstructured-io |
+
+
+ Compound Name: Iwilfin ([1], [2], [3], [4]) (eflornithine) ([0], [2], [3], [4])
+
+ Indication: Iwilfin is indicated to reduce the risk of relapse ([1], [3]) in adult and paediatric patients ([1], [3]) with high-risk neuroblastoma (HRNB) ([1], [3]), who have responded to prior anti-GD2 ([1]) immunotherapy ([1], [4]) and multi-modality therapy. ([1])
+
+ Route of Administration: Oral ([0], [3])
+
+ Mechanism of Action: Iwilfin is an ornithine decarboxylase inhibitor. ([1], [2], [3], [4])
+
+
+ | llamaparse-text |
+
+
+ Compound Name: IWILFIN ([2], [3]) (eflornithine) ([3])
+
+ Indication: IWILFIN is used to reduce the risk of relapse ([1], [2], [3]) in adult and paediatric patients ([1], [2], [3]) with high-risk neuroblastoma (HRNB) ([1], [2], [3]), who have responded at least partially to certain prior therapies. ([2], [3])
+
+ Route of Administration: IWILFIN is administered as a tablet. ([2])
+
+ Mechanism of Action: IWILFIN is an ornithine decarboxylase inhibitor. ([0], [1], [4])
+
+
+ | llamaparse-markdown |
+
+
+ Compound Name: IWILFIN ([1], [2]) (eflornithine) ([1])
+
+ Indication: IWILFIN is indicated to reduce the risk of relapse ([1], [2]) in adult and paediatric patients ([1], [2]) with high-risk neuroblastoma (HRNB) ([1], [2]), who have responded at least partially ([1], [2], [3]) to prior anti-GD2 immunotherapy ([1], [2]) and multiagent, multimodality therapy. ([1], [2], [3])
+
+ Route of Administration: Oral ([0], [1], [3], [4])
+
+ Mechanism of Action: IWILFIN acts as an ornithine decarboxylase inhibitor. ([1])
+
+
+ | pytesseract |
+
+
+ Compound Name: IWILFIN™ ([0], [2]) (eflornithine) ([0], [2])
+
+ Indication: IWILFIN is indicated to reduce the risk of relapse ([0], [2]) in adult and paediatric patients ([0], [2]) with high-risk neuroblastoma (HRNB) ([0], [2]), who have responded positively to prior anti-GD2 immunotherapy and multiagent, multimodality therapy. ([0], [2], [4])
+
+ Route of Administration: IWILFIN is administered orally ([0], [1], [3], [4]), in the form of a tablet. ([1])
+
+ Mechanism of Action: IWILFIN acts as an ornithine decarboxylase inhibitor. ([0])
+
+
-
-Compound Name: eflornithine ([0], [1], [2], [3]) (IWILFIN ([0])™)
-
-Indication: used to reduce the risk of relapse ([0], [3]) in adults ([0], [3]) and paediatric patients ([0], [3]) with high-risk neuroblastoma (HRNB) ([0], [3]) who have responded to prior therapies. ([0], [3], [4])
-
-Route of Administration: Oral ([2], [4])
-
-Mechanism of Action: IWILFIN is an ornithine decarboxylase inhibitor. ([1])
-
-
-| unstructured-io |
-
-
-Compound Name: Iwilfin ([1], [2], [3], [4]) (eflornithine) ([0], [2], [3], [4])
-
-Indication: Iwilfin is indicated to reduce the risk of relapse ([1], [3]) in adult and paediatric patients ([1], [3]) with high-risk neuroblastoma (HRNB) ([1], [3]), who have responded to prior anti-GD2 ([1]) immunotherapy ([1], [4]) and multi-modality therapy. ([1])
-
-Route of Administration: Oral ([0], [3])
-
-Mechanism of Action: Iwilfin is an ornithine decarboxylase inhibitor. ([1], [2], [3], [4])
-
-
-| llamaparse-text |
-
-
-Compound Name: IWILFIN ([2], [3]) (eflornithine) ([3])
-
-Indication: IWILFIN is used to reduce the risk of relapse ([1], [2], [3]) in adult and paediatric patients ([1], [2], [3]) with high-risk neuroblastoma (HRNB) ([1], [2], [3]), who have responded at least partially to certain prior therapies. ([2], [3])
-
-Route of Administration: IWILFIN is administered as a tablet. ([2])
-
-Mechanism of Action: IWILFIN is an ornithine decarboxylase inhibitor. ([0], [1], [4])
-
-
-| llamaparse-markdown |
-
-
-Compound Name: IWILFIN ([1], [2]) (eflornithine) ([1])
-
-Indication: IWILFIN is indicated to reduce the risk of relapse ([1], [2]) in adult and paediatric patients ([1], [2]) with high-risk neuroblastoma (HRNB) ([1], [2]), who have responded at least partially ([1], [2], [3]) to prior anti-GD2 immunotherapy ([1], [2]) and multiagent, multimodality therapy. ([1], [2], [3])
-
-Route of Administration: Oral ([0], [1], [3], [4])
-
-Mechanism of Action: IWILFIN acts as an ornithine decarboxylase inhibitor. ([1])
-
-
-| pytesseract |
-
-
-Compound Name: IWILFIN™ ([0], [2]) (eflornithine) ([0], [2])
-
-Indication: IWILFIN is indicated to reduce the risk of relapse ([0], [2]) in adult and paediatric patients ([0], [2]) with high-risk neuroblastoma (HRNB) ([0], [2]), who have responded positively to prior anti-GD2 immunotherapy and multiagent, multimodality therapy. ([0], [2], [4])
-
-Route of Administration: IWILFIN is administered orally ([0], [1], [3], [4]), in the form of a tablet. ([1])
-
-Mechanism of Action: IWILFIN acts as an ornithine decarboxylase inhibitor. ([0])
-```
diff --git a/fern/pages/cookbooks/elasticsearch-and-cohere.mdx b/fern/pages/cookbooks/elasticsearch-and-cohere.mdx
index c4f6bdb06..6019f1f70 100644
--- a/fern/pages/cookbooks/elasticsearch-and-cohere.mdx
+++ b/fern/pages/cookbooks/elasticsearch-and-cohere.mdx
@@ -3,28 +3,38 @@ title: End-to-end RAG using Elasticsearch and Cohere
slug: /page/elasticsearch-and-cohere
description: "This page contains a basic tutorial on how to get Cohere and ElasticSearch to work well together."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, ElasticSearch"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
Learn how to use the [Inference API](https://www.elastic.co/guide/en/elasticsearch/reference/current/inference-apis.html) for semantic search and use [Cohere's APIs](https://docs.cohere.com/docs/the-cohere-platform) for RAG.
+# 🧰 Requirements
+
For this example, you will need:
- An Elastic Serverless account through [Elastic Cloud](https://www.elastic.co/guide/en/cloud/current/ec-getting-started.html), available with a [free trial](https://cloud.elastic.co/registration?utm_source=github&utm_content=elasticsearch-labs-notebook)
+
- A [Cohere account](https://cohere.com/) with a production API key
- Python 3.7 or higher
Note: While this tutorial integrates Cohere with an Elastic Cloud serverless project, you can also integrate with your self-managed Elasticsearch deployment or Elastic Cloud deployment by simply switching from using a Serverless endpoint in the Elasticsearch client.
+# Create an Elastic Serverless deployment
+
If you don't have an Elastic Cloud deployment, sign up [here](https://cloud.elastic.co/registration?utm_source=github&utm_content=elasticsearch-labs-notebook) for a free trial and request access to Elastic Serverless
+# Install packages and connect with Elasticsearch Serverless Client
+
To get started, we'll need to connect to our Elastic Serverless deployment using the Python client.
First we need to `pip` install the following packages:
@@ -34,13 +44,15 @@ First we need to `pip` install the following packages:
After installing, in the Serverless dashboard, find your endpoint URL, and create your API key.
-```python PYTHON
+
+```python
pip install elasticsearch_serverless cohere
```
Next, we need to import the modules we need. 🔐 NOTE: getpass enables us to securely prompt the user for credentials without echoing them to the terminal, or storing it in memory.
-```python PYTHON
+
+```python
from elasticsearch_serverless import Elasticsearch, helpers
from getpass import getpass
import cohere
@@ -48,6 +60,8 @@ import json
import requests
```
+
+
Now we can instantiate the Python Elasticsearch client.
First we prompt the user for their endpoint and encoded API key.
@@ -55,7 +69,8 @@ Then we create a `client` object that instantiates an instance of the `Elasticse
When creating your Elastic Serverless API key make sure to turn on Control security privileges, and edit cluster privileges to specify `"cluster": ["all"]`
-```python PYTHON
+
+```python
ELASTICSEARCH_ENDPOINT = getpass("Elastic Endpoint: ")
ELASTIC_API_KEY = getpass("Elastic encoded API key: ") # Use the encoded API key
@@ -67,7 +82,8 @@ client = Elasticsearch(
Confirm that the client has connected with this test:
-```python PYTHON
+
+```python
print(client.info())
```
@@ -77,9 +93,13 @@ Let's create the inference endpoint by using the [Create inference API](https://
You'll need an Cohere API key for this that you can find in your Cohere account under the [API keys section](https://dashboard.cohere.com/api-keys). A production key is required to complete the steps in this notebook as the Cohere free trial API usage is limited.
-```python PYTHON
+
+
+
+```python
COHERE_API_KEY = getpass("Enter Cohere API key: ")
+# Delete the inference model if it already exists
client.options(ignore_status=[404]).inference.delete_model(inference_id="cohere_embeddings")
client.inference.put_model(
@@ -102,7 +122,9 @@ client.inference.put_model(
Create an ingest pipeline with an inference processor by using the [`put_pipeline`](https://www.elastic.co/guide/en/elasticsearch/reference/master/put-pipeline-api.html) method. Reference the inference endpoint created above as the `model_id` to infer against the data that is being ingested in the pipeline.
-```python PYTHON
+
+```python
+# Delete the inference pipeline if it already exists
client.options(ignore_status=[404]).ingest.delete_pipeline(id="cohere_embeddings")
client.ingest.put_pipeline(
@@ -128,7 +150,7 @@ Let's note a few important parameters from that API call:
- `model_id`: Specifies the ID of the inference endpoint to be used. In this example, the model ID is set to `cohere_embeddings`.
- `input_output`: Specifies input and output fields.
- `input_field`: Field name from which the `dense_vector` representation is created.
-- `output_field`: Field name which contains inference results.
+- `output_field`: Field name which contains inference results.
## Create index
@@ -136,7 +158,8 @@ The mapping of the destination index – the index that contains the embeddings
Let's create an index named `cohere-wiki-embeddings` with the mappings we need.
-```python PYTHON
+
+```python
client.indices.delete(index="cohere-wiki-embeddings", ignore_unavailable=True)
client.indices.create(
index="cohere-wiki-embeddings",
@@ -165,12 +188,15 @@ client.indices.create(
Let's insert our example wiki dataset. You need a production Cohere account to complete this step, otherwise the documentation ingest will time out due to the API request rate limits.
-```python PYTHON
+
+```python
url = "https://raw.githubusercontent.com/cohere-ai/cohere-developer-experience/main/notebooks/data/embed_jobs_sample_data.jsonl"
response = requests.get(url)
+# Load the response data into a JSON object
jsonl_data = response.content.decode('utf-8').splitlines()
+# Prepare the documents to be indexed
documents = []
for line in jsonl_data:
data_dict = json.loads(line)
@@ -180,6 +206,7 @@ for line in jsonl_data:
}
)
+# Use the bulk endpoint to index
helpers.bulk(client, documents)
print("Done indexing documents into `cohere-wiki-embeddings` index!")
@@ -191,7 +218,8 @@ After the dataset has been enriched with the embeddings, you can query the data
Pass a `query_vector_builder` to the k-nearest neighbor (kNN) vector search API, and provide the query text and the model you have used to create the embeddings.
-```python PYTHON
+
+```python
query = "When were the semi-finals of the 2022 FIFA world cup played?"
response = client.search(
@@ -218,21 +246,24 @@ response = client.search(
raw_documents = response["hits"]["hits"]
+# Display the first 10 results
for document in raw_documents[0:10]:
print(f'Title: {document["_source"]["title"]}\nText: {document["_source"]["text"]}\n')
+# Format the documents for ranking
documents = []
for hit in response["hits"]["hits"]:
documents.append(hit["_source"]["text"])
```
## Ranking
-
In order to effectively combine the results from our vector and BM25 retrieval, we can use Cohere's Rerank 3 model through the inference API to provide a final, more precise, semantic reranking of our results.
First, create an inference endpoint with your Cohere API key. Make sure to specify a name for your endpoint, and the model_id of one of the rerank models. In this example we will use Rerank 3.
-```python PYTHON
+
+```python
+# Delete the inference model if it already exists
client.options(ignore_status=[404]).inference.delete_model(inference_id="cohere_rerank")
client.inference.put_model(
@@ -257,7 +288,8 @@ The inference service will respond with a list of documents in descending order
In this case we will set the response to False and will reconstruct the input documents based on the index returned in the response.
-```python PYTHON
+
+```python
response = client.inference.inference(
inference_id="cohere_rerank",
body={
@@ -269,6 +301,7 @@ response = client.inference.inference(
}
)
+# Reconstruct the input documents based on the index provided in the rereank response
ranked_documents = []
for document in response.body["rerank"]:
ranked_documents.append({
@@ -276,21 +309,26 @@ for document in response.body["rerank"]:
"text": raw_documents[int(document["index"])]["_source"]["text"]
})
+# Print the top 10 results
for document in ranked_documents[0:10]:
print(f"Title: {document['title']}\nText: {document['text']}\n")
```
+# Retrieval augemented generation
+
Now that we have ranked our results, we can easily turn this into a RAG system with Cohere's Chat API. Pass in the retrieved documents, along with the query and see the grounded response using Cohere's newest generative model Command R+.
First, we will create the Cohere client.
-```python PYTHON
+
+```python
co = cohere.Client(COHERE_API_KEY)
```
Next, we can easily get a grounded generation with citations from the Cohere Chat API. We simply pass in the user query and documents retrieved from Elastic to the API, and print out our grounded response.
-```python PYTHON
+
+```python
response = co.chat(
message=query,
documents=ranked_documents,
diff --git a/fern/pages/cookbooks/embed-jobs-serverless-pinecone.mdx b/fern/pages/cookbooks/embed-jobs-serverless-pinecone.mdx
index d64fac3e6..65783b786 100644
--- a/fern/pages/cookbooks/embed-jobs-serverless-pinecone.mdx
+++ b/fern/pages/cookbooks/embed-jobs-serverless-pinecone.mdx
@@ -1,18 +1,28 @@
---
-title: Serverless Semantic Search with Cohere and Pinecone
+title: Semantic Search with Cohere Embed Jobs and Pinecone serverless Solution
slug: /page/embed-jobs-serverless-pinecone
description: "This page contains a basic tutorial on how to get Cohere and the Pinecone vector database to work well together."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, Pinecone"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-```python PYTHON
+
+
+
+
+
+```python
+# TODO: upgrade to "cohere>5"
+! pip install "cohere<5" "pinecone-client>3.2.1"
+```
+
+
+```python
import os
import json
import time
@@ -22,19 +32,20 @@ from pinecone import Pinecone
co = cohere.Client('COHERE_API_KEY')
pc = Pinecone(
- api_key="PINECONE_API_KEY",
+ api_key="PINECONE_API_KEY",
source_tag="cohere"
)
```
-```txt title="Output"
-/usr/local/lib/python3.10/dist-packages/pinecone/data/index.py:1: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)
- from tqdm.autonotebook import tqdm
-```
+ /usr/local/lib/python3.10/dist-packages/pinecone/data/index.py:1: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)
+ from tqdm.autonotebook import tqdm
+
## Step 1: Upload a dataset
-```python PYTHON
+
+```python
+# Upload a dataset for embed jobs
dataset_file_path = "data/embed_jobs_sample_data.jsonl" # Full path - https://raw.githubusercontent.com/cohere-ai/cohere-developer-experience/main/notebooks/data/embed_jobs_sample_data.jsonl
ds=co.create_dataset(
@@ -47,77 +58,39 @@ ds=co.create_dataset(
print(ds.await_validation())
```
-```txt title="Output"
-uploading file, starting validation...
-sample-file-2gwgxq was uploaded
-...
-
-
-cohere.Dataset {
- id: sample-file-2gwgxq
- name: sample_file
- dataset_type: embed-input
- validation_status: validated
- created_at: 2024-01-13 02:47:32.563080
- updated_at: 2024-01-13 02:47:32.563081
- download_urls: ['']
- validation_error: None
- validation_warnings: []
-}
-```
-
## Step 2: Create embeddings via Cohere's Embed Jobs endpoint
-```python PYTHON
+
+```python
+# Dataset has been uploaded, create an embed job and specify the input type as "search document" since this will live in your Pinecone DB
job = co.create_embed_job(dataset_id=ds.id,
input_type='search_document',
model='embed-english-v3.0',
embeddings_types=['float'])
-job.wait() # poll the server until the job is completed
+job.wait() # poll the server until the job is completed
```
-```txt title="Output"
-...
-...
-```
+ ...
+ ...
+
-```python PYTHON
-print(job)
-```
-```bash title="Output"
-cohere.EmbedJob {
- job_id: 6d691fbe-e026-436a-826a-16e70b293e51
- status: complete
- created_at: 2024-01-13T02:47:46.385016Z
- input_dataset_id: sample-file-2gwgxq
- output_urls: None
- model: embed-english-v3.0
- truncate: RIGHT
- percent_complete: 100
- output: cohere.Dataset {
- id: embeded-sample-file-mdse2h
- name: embeded-sample-file
- dataset_type: embed-result
- validation_status: validated
- created_at: 2024-01-13 02:47:47.850097
- updated_at: 2024-01-13 02:47:47.850097
- download_urls: ['']
- validation_error: None
- validation_warnings: []
- }
-}
+```python
+print(job)
```
## Step 3: Prepare embeddings for upsert
-```python PYTHON
+
+```python
+# Load the output file into an array
output_dataset=co.get_dataset(job.output.id)
data_array = []
for record in output_dataset:
data_array.append(record)
+# Take the output and format it in the shape for upserting into Pinecone's DB
ids = [str(i) for i in range(len(data_array))]
meta = [{'text':str(data_array[i]['text'])} for i in range(len(data_array))]
embeds=[np.float32(data_array[i]['embeddings']['float']) for i in range(len(data_array))]
@@ -127,11 +100,14 @@ to_upsert = list(zip(ids, embeds, meta))
## Step 4: Initialize Pinecone vector database
-```python PYTHON
+
+```python
+# Initialize your Pinecone Vector DB
from pinecone import ServerlessSpec
index_name = "embed-jobs-serverless-test-example"
+# A new property 'spec' is used to tell Pinecone how we should deploy your index.
pc.create_index(
name=index_name,
dimension=1024,
@@ -139,33 +115,39 @@ metric="cosine",
spec=ServerlessSpec(cloud='aws', region='us-west-2')
)
+# Target your new serverless index.
idx = pc.Index(index_name)
```
## Step 5: Upsert embeddings into the index
-```python PYTHON
+
+```python
+# Upsert your data into the index
batch_size = 128
for i in range(0, len(data_array), batch_size):
i_end = min(i+batch_size, len(data_array))
idx.upsert(vectors=to_upsert[i:i_end])
+# let's view the index statistics
print(idx.describe_index_stats())
```
-```txt title="Output"
-{'dimension': 1024,
-'index_fullness': 0.0,
-'namespaces': {'': {'vector_count': 3664}},
-'total_vector_count': 3664}
-```
+ {'dimension': 1024,
+ 'index_fullness': 0.0,
+ 'namespaces': {'': {'vector_count': 3664}},
+ 'total_vector_count': 3664}
+
## Step 6: Query the index
-```python PYTHON
+
+```python
+# Let's query the database
query = "What did Microsoft announce in Las Vegas?"
+# create the query embedding
xq = co.embed(
texts=[query],
model='embed-english-v3.0',
@@ -175,44 +157,47 @@ xq = co.embed(
print(np.array(xq).shape)
+# query, returning the top 20 most similar results
res = idx.query(xq, top_k=20, include_metadata=True)
```
-```txt title="Output"
-(1, 1024)
-```
+ (1, 1024)
+
-```python PYTHON
+
+```python
+# Look at the initial retrieval results
for match in res['matches']:
print(f"{match['score']:.2f}: {match['metadata']['text']}")
```
-```txt title="Output"
-0.48: On October 22, 2012, Microsoft announced the release of new features including co-authoring, performance improvements and touch support.
-0.45: On May 2, 2019, at F8, the company announced its new vision with the tagline "the future is private". A redesign of the website and mobile app was introduced, dubbed as "FB5". The event also featured plans for improving groups, a dating platform, end-to-end encryption on its platforms, and allowing users on Messenger to communicate directly with WhatsApp and Instagram users.
-0.42: On July 13, 2009, Microsoft announced at its Worldwide Partners Conference 2009 in New Orleans that Microsoft Office 2010 reached its "Technical Preview" development milestone and features of Office Web Apps were demonstrated to the public for the first time. Additionally, Microsoft announced that Office Web Apps would be made available to consumers online and free of charge, while Microsoft Software Assurance customers will have the option of running them on premises. Office 2010 beta testers were not given access to Office Web Apps at this date, and it was announced that it would be available for testers during August 2009. However, in August 2009, a Microsoft spokesperson stated that there had been a delay in the release of Office Web Apps Technical Preview and it would not be available by the end of August.
-0.42: On January 17, 2017, Facebook COO Sheryl Sandberg planned to open Station F, a startup incubator campus in Paris, France. On a six-month cycle, Facebook committed to work with ten to 15 data-driven startups there. On April 18, Facebook announced the beta launch of at its annual F8 developer conference. Facebook Spaces is a virtual reality version of Facebook for Oculus VR goggles. In a virtual and shared space, users can access a curated selection of 360-degree photos and videos using their avatar, with the support of the controller. Users can access their own photos and videos, along with media shared on their newsfeed. In September, Facebook announced it would spend up to US$1 billion on original shows for its Facebook Watch platform. On October 16, it acquired the anonymous compliment app tbh, announcing its intention to leave the app independent.
-0.41: On September 26, 2017, Microsoft announced that the next version of the suite for Windows desktop, Office 2019, was in development. On April 27, 2018, Microsoft released Office 2019 Commercial Preview for Windows 10. It was released to general availability for Windows 10 and for macOS on September 24, 2018.
-0.41: Microsoft Office, or simply Office, is the former name of a family of client software, server software, and services developed by Microsoft. It was first announced by Bill Gates on August 1, 1988, at COMDEX in Las Vegas. Initially a marketing term for an office suite (bundled set of productivity applications), the first version of Office contained Microsoft Word, Microsoft Excel, and Microsoft PowerPoint. Over the years, Office applications have grown substantially closer with shared features such as a common spell checker, Object Linking and Embedding data integration and Visual Basic for Applications scripting language. Microsoft also positions Office as a development platform for line-of-business software under the Office Business Applications brand.
-0.40: On August 12, 2009, it was announced that Office Mobile would also be released for the Symbian platform as a joint agreement between Microsoft and Nokia. It was the first time Microsoft would develop Office mobile applications for another smartphone platform. The first application to appear on Nokia Eseries smartphones was Microsoft Office Communicator. In February 2012, Microsoft released OneNote, Lync 2010, Document Connection and PowerPoint Broadcast for Symbian. In April, Word Mobile, PowerPoint Mobile and Excel Mobile joined the Office Suite.
-0.40: In 2010, Microsoft introduced a software as a service platform known as Office 365, to provide cloud-hosted versions of Office's server software, including Exchange e-mail and SharePoint, on a subscription basis (competing in particular with Google Apps). Following the release of Office 2013, Microsoft began to offer Office 365 plans for the consumer market, with access to Microsoft Office software on multiple devices with free feature updates over the life of the subscription, as well as other services such as OneDrive storage.
-0.40: On April 12, 2016, Zuckerberg outlined his 10-year vision, which rested on three main pillars: artificial intelligence, increased global connectivity, and virtual and augmented reality. In July, a suit was filed against the company alleging that it permitted Hamas to use it to perform assaults that cost the lives of four people. Facebook released its blueprints of Surround 360 camera on GitHub under an open-source license. In September, it won an Emmy for its animated short "Henry". In October, Facebook announced a fee-based communications tool called Workplace that aims to "connect everyone" at work. Users can create profiles, see updates from co-workers on their news feed, stream live videos and participate in secure group chats.
-0.40: On January 22, 2015, the Microsoft Office blog announced that the next version of the suite for Windows desktop, Office 2016, was in development. On May 4, 2015, a public preview of Microsoft Office 2016 was released. Office 2016 was released for Mac OS X on July 9, 2015 and for Windows on September 22, 2015.
-0.39: On November 6, 2013, Microsoft announced further new features including "real-time" co-authoring and an Auto-Save feature in Word (replacing the save button).
-0.39: In February 2014, Office Web Apps were re-branded Office Online and incorporated into other Microsoft web services, including Calendar, OneDrive, Outlook.com, and People. Microsoft had previously attempted to unify its online services suite (including Microsoft Passport, Hotmail, MSN Messenger, and later SkyDrive) under a brand known as Windows Live, first launched in 2005. However, with the impending launch of Windows 8 and its increased use of cloud services, Microsoft dropped the Windows Live brand to emphasize that these services would now be built directly into Windows and not merely be a "bolted on" add-on. Critics had criticized the Windows Live brand for having no clear vision, as it was being applied to an increasingly broad array of unrelated services. At the same time, Windows Live Hotmail was re-launched as Outlook.com (sharing its name with the Microsoft Outlook personal information manager).
-0.39: On February 18, 2021, Microsoft announced that the next version of the suite for Windows desktop, Office 2021, was in development. This new version will be supported for five years and was released on October 5, 2021.
-0.38: Since Office 2013, Microsoft has promoted Office 365 as the primary means of obtaining Microsoft Office: it allows the use of the software and other services on a subscription business model, and users receive feature updates to the software for the lifetime of the subscription, including new features and cloud computing integration that are not necessarily included in the "on-premises" releases of Office sold under conventional license terms. In 2017, revenue from Office 365 overtook conventional license sales. Microsoft also rebranded most of their standard Office 365 editions as "Microsoft 365" to reflect their inclusion of features and services beyond the core Microsoft Office suite.
-0.38: Microsoft has since promoted Office 365 as the primary means of purchasing Microsoft Office. Although there are still "on-premises" releases roughly every three years, Microsoft marketing emphasizes that they do not receive new features or access to new cloud-based services as they are released unlike Office 365, as well as other benefits for consumer and business markets. Office 365 revenue overtook traditional license sales for Office in 2017.
-0.38: A technical preview of Microsoft Office 2013 (Build 15.0.3612.1010) was released on January 30, 2012, and a Customer Preview version was made available to consumers on July 16, 2012. It sports a revamped application interface; the interface is based on Metro, the interface of Windows Phone and Windows 8. Microsoft Outlook has received the most pronounced changes so far; for example, the Metro interface provides a new visualization for scheduled tasks. PowerPoint includes more templates and transition effects, and OneNote includes a new splash screen.
-0.38: On January 21, 2015, during the "Windows 10: The Next Chapter" press event, Microsoft unveiled Office for Windows 10, Windows Runtime ports of the Android and iOS versions of the Office Mobile suite. Optimized for smartphones and tablets, they are universal apps that can run on both Windows and Windows for phones, and share similar underlying code. A simplified version of Outlook was also added to the suite. They will be bundled with Windows 10 mobile devices, and available from the Windows Store for the PC version of Windows 10. Although the preview versions were free for most editing, the release versions will require an Office 365 subscription on larger tablets (screen size larger than 10.1 inches) and desktops for editing, as with large Android tablets. Smaller tablets and phones will have most editing features for free.
-0.38: In May 2018 at F8, the company announced it would offer its own dating service. Shares in competitor Match Group fell by 22%. Facebook Dating includes privacy features and friends are unable to view their friends' dating profile. In July, Facebook was charged £500,000 by UK watchdogs for failing to respond to data erasure requests. On July 18, Facebook established a subsidiary named Lianshu Science & Technology in Hangzhou City, China, with $30 million ($ in dollars) of capital. All its shares are held by Facebook Hong. Approval of the registration of the subsidiary was then withdrawn, due to a disagreement between officials in Zhejiang province and the Cyberspace Administration of China. On July 26, Facebook became the first company to lose over $100 billion ($ in dollars) worth of market capitalization in one day, dropping from nearly $630 billion to $510 billion after disappointing sales reports. On July 31, Facebook said that the company had deleted 17 accounts related to the 2018 U.S. midterm elections. On September 19, Facebook announced that, for news distribution outside the United States, it would work with U.S. funded democracy promotion organizations, International Republican Institute and the National Democratic Institute, which are loosely affiliated with the Republican and Democratic parties. Through the Digital Forensic Research Lab Facebook partners with the Atlantic Council, a NATO-affiliated think tank. In November, Facebook launched smart displays branded Portal and Portal Plus (Portal+). They support Amazon's Alexa (intelligent personal assistant service). The devices include video chat function with Facebook Messenger.
-0.37: The first Preview version of Microsoft Office 2016 for Mac was released on March 5, 2015. On July 9, 2015, Microsoft released the final version of Microsoft Office 2016 for Mac which includes Word, Excel, PowerPoint, Outlook and OneNote. It was immediately made available for Office 365 subscribers with either a Home, Personal, Business, Business Premium, E3 or ProPlus subscription. A non–Office 365 edition of Office 2016 was made available as a one-time purchase option on September 22, 2015.
-0.37: In October 2022, Microsoft announced that it will phase out the Microsoft Office brand in favor of "Microsoft 365" by January 2023. The name will continue to be used for legacy product offerings.
-```
+ 0.48: On October 22, 2012, Microsoft announced the release of new features including co-authoring, performance improvements and touch support.
+ 0.45: On May 2, 2019, at F8, the company announced its new vision with the tagline "the future is private". A redesign of the website and mobile app was introduced, dubbed as "FB5". The event also featured plans for improving groups, a dating platform, end-to-end encryption on its platforms, and allowing users on Messenger to communicate directly with WhatsApp and Instagram users.
+ 0.42: On July 13, 2009, Microsoft announced at its Worldwide Partners Conference 2009 in New Orleans that Microsoft Office 2010 reached its "Technical Preview" development milestone and features of Office Web Apps were demonstrated to the public for the first time. Additionally, Microsoft announced that Office Web Apps would be made available to consumers online and free of charge, while Microsoft Software Assurance customers will have the option of running them on premises. Office 2010 beta testers were not given access to Office Web Apps at this date, and it was announced that it would be available for testers during August 2009. However, in August 2009, a Microsoft spokesperson stated that there had been a delay in the release of Office Web Apps Technical Preview and it would not be available by the end of August.
+ 0.42: On January 17, 2017, Facebook COO Sheryl Sandberg planned to open Station F, a startup incubator campus in Paris, France. On a six-month cycle, Facebook committed to work with ten to 15 data-driven startups there. On April 18, Facebook announced the beta launch of at its annual F8 developer conference. Facebook Spaces is a virtual reality version of Facebook for Oculus VR goggles. In a virtual and shared space, users can access a curated selection of 360-degree photos and videos using their avatar, with the support of the controller. Users can access their own photos and videos, along with media shared on their newsfeed. In September, Facebook announced it would spend up to US$1 billion on original shows for its Facebook Watch platform. On October 16, it acquired the anonymous compliment app tbh, announcing its intention to leave the app independent.
+ 0.41: On September 26, 2017, Microsoft announced that the next version of the suite for Windows desktop, Office 2019, was in development. On April 27, 2018, Microsoft released Office 2019 Commercial Preview for Windows 10. It was released to general availability for Windows 10 and for macOS on September 24, 2018.
+ 0.41: Microsoft Office, or simply Office, is the former name of a family of client software, server software, and services developed by Microsoft. It was first announced by Bill Gates on August 1, 1988, at COMDEX in Las Vegas. Initially a marketing term for an office suite (bundled set of productivity applications), the first version of Office contained Microsoft Word, Microsoft Excel, and Microsoft PowerPoint. Over the years, Office applications have grown substantially closer with shared features such as a common spell checker, Object Linking and Embedding data integration and Visual Basic for Applications scripting language. Microsoft also positions Office as a development platform for line-of-business software under the Office Business Applications brand.
+ 0.40: On August 12, 2009, it was announced that Office Mobile would also be released for the Symbian platform as a joint agreement between Microsoft and Nokia. It was the first time Microsoft would develop Office mobile applications for another smartphone platform. The first application to appear on Nokia Eseries smartphones was Microsoft Office Communicator. In February 2012, Microsoft released OneNote, Lync 2010, Document Connection and PowerPoint Broadcast for Symbian. In April, Word Mobile, PowerPoint Mobile and Excel Mobile joined the Office Suite.
+ 0.40: In 2010, Microsoft introduced a software as a service platform known as Office 365, to provide cloud-hosted versions of Office's server software, including Exchange e-mail and SharePoint, on a subscription basis (competing in particular with Google Apps). Following the release of Office 2013, Microsoft began to offer Office 365 plans for the consumer market, with access to Microsoft Office software on multiple devices with free feature updates over the life of the subscription, as well as other services such as OneDrive storage.
+ 0.40: On April 12, 2016, Zuckerberg outlined his 10-year vision, which rested on three main pillars: artificial intelligence, increased global connectivity, and virtual and augmented reality. In July, a suit was filed against the company alleging that it permitted Hamas to use it to perform assaults that cost the lives of four people. Facebook released its blueprints of Surround 360 camera on GitHub under an open-source license. In September, it won an Emmy for its animated short "Henry". In October, Facebook announced a fee-based communications tool called Workplace that aims to "connect everyone" at work. Users can create profiles, see updates from co-workers on their news feed, stream live videos and participate in secure group chats.
+ 0.40: On January 22, 2015, the Microsoft Office blog announced that the next version of the suite for Windows desktop, Office 2016, was in development. On May 4, 2015, a public preview of Microsoft Office 2016 was released. Office 2016 was released for Mac OS X on July 9, 2015 and for Windows on September 22, 2015.
+ 0.39: On November 6, 2013, Microsoft announced further new features including "real-time" co-authoring and an Auto-Save feature in Word (replacing the save button).
+ 0.39: In February 2014, Office Web Apps were re-branded Office Online and incorporated into other Microsoft web services, including Calendar, OneDrive, Outlook.com, and People. Microsoft had previously attempted to unify its online services suite (including Microsoft Passport, Hotmail, MSN Messenger, and later SkyDrive) under a brand known as Windows Live, first launched in 2005. However, with the impending launch of Windows 8 and its increased use of cloud services, Microsoft dropped the Windows Live brand to emphasize that these services would now be built directly into Windows and not merely be a "bolted on" add-on. Critics had criticized the Windows Live brand for having no clear vision, as it was being applied to an increasingly broad array of unrelated services. At the same time, Windows Live Hotmail was re-launched as Outlook.com (sharing its name with the Microsoft Outlook personal information manager).
+ 0.39: On February 18, 2021, Microsoft announced that the next version of the suite for Windows desktop, Office 2021, was in development. This new version will be supported for five years and was released on October 5, 2021.
+ 0.38: Since Office 2013, Microsoft has promoted Office 365 as the primary means of obtaining Microsoft Office: it allows the use of the software and other services on a subscription business model, and users receive feature updates to the software for the lifetime of the subscription, including new features and cloud computing integration that are not necessarily included in the "on-premises" releases of Office sold under conventional license terms. In 2017, revenue from Office 365 overtook conventional license sales. Microsoft also rebranded most of their standard Office 365 editions as "Microsoft 365" to reflect their inclusion of features and services beyond the core Microsoft Office suite.
+ 0.38: Microsoft has since promoted Office 365 as the primary means of purchasing Microsoft Office. Although there are still "on-premises" releases roughly every three years, Microsoft marketing emphasizes that they do not receive new features or access to new cloud-based services as they are released unlike Office 365, as well as other benefits for consumer and business markets. Office 365 revenue overtook traditional license sales for Office in 2017.
+ 0.38: A technical preview of Microsoft Office 2013 (Build 15.0.3612.1010) was released on January 30, 2012, and a Customer Preview version was made available to consumers on July 16, 2012. It sports a revamped application interface; the interface is based on Metro, the interface of Windows Phone and Windows 8. Microsoft Outlook has received the most pronounced changes so far; for example, the Metro interface provides a new visualization for scheduled tasks. PowerPoint includes more templates and transition effects, and OneNote includes a new splash screen.
+ 0.38: On January 21, 2015, during the "Windows 10: The Next Chapter" press event, Microsoft unveiled Office for Windows 10, Windows Runtime ports of the Android and iOS versions of the Office Mobile suite. Optimized for smartphones and tablets, they are universal apps that can run on both Windows and Windows for phones, and share similar underlying code. A simplified version of Outlook was also added to the suite. They will be bundled with Windows 10 mobile devices, and available from the Windows Store for the PC version of Windows 10. Although the preview versions were free for most editing, the release versions will require an Office 365 subscription on larger tablets (screen size larger than 10.1 inches) and desktops for editing, as with large Android tablets. Smaller tablets and phones will have most editing features for free.
+ 0.38: In May 2018 at F8, the company announced it would offer its own dating service. Shares in competitor Match Group fell by 22%. Facebook Dating includes privacy features and friends are unable to view their friends' dating profile. In July, Facebook was charged £500,000 by UK watchdogs for failing to respond to data erasure requests. On July 18, Facebook established a subsidiary named Lianshu Science & Technology in Hangzhou City, China, with $30 million ($ in dollars) of capital. All its shares are held by Facebook Hong. Approval of the registration of the subsidiary was then withdrawn, due to a disagreement between officials in Zhejiang province and the Cyberspace Administration of China. On July 26, Facebook became the first company to lose over $100 billion ($ in dollars) worth of market capitalization in one day, dropping from nearly $630 billion to $510 billion after disappointing sales reports. On July 31, Facebook said that the company had deleted 17 accounts related to the 2018 U.S. midterm elections. On September 19, Facebook announced that, for news distribution outside the United States, it would work with U.S. funded democracy promotion organizations, International Republican Institute and the National Democratic Institute, which are loosely affiliated with the Republican and Democratic parties. Through the Digital Forensic Research Lab Facebook partners with the Atlantic Council, a NATO-affiliated think tank. In November, Facebook launched smart displays branded Portal and Portal Plus (Portal+). They support Amazon's Alexa (intelligent personal assistant service). The devices include video chat function with Facebook Messenger.
+ 0.37: The first Preview version of Microsoft Office 2016 for Mac was released on March 5, 2015. On July 9, 2015, Microsoft released the final version of Microsoft Office 2016 for Mac which includes Word, Excel, PowerPoint, Outlook and OneNote. It was immediately made available for Office 365 subscribers with either a Home, Personal, Business, Business Premium, E3 or ProPlus subscription. A non–Office 365 edition of Office 2016 was made available as a one-time purchase option on September 22, 2015.
+ 0.37: In October 2022, Microsoft announced that it will phase out the Microsoft Office brand in favor of "Microsoft 365" by January 2023. The name will continue to be used for legacy product offerings.
+
## Step 7: Rerank the retrieved results
-```python PYTHON
+
+```python
+# Add Cohere Reranking Step
docs =[match['metadata']['text'] for match in res['matches']]
rerank_response = co.rerank(
@@ -225,17 +210,19 @@ for response in rerank_response:
print(f"{response.relevance_score:.2f}: {response.document['text']}")
```
-```txt title="Output"
-0.99: Microsoft Office, or simply Office, is the former name of a family of client software, server software, and services developed by Microsoft. It was first announced by Bill Gates on August 1, 1988, at COMDEX in Las Vegas. Initially a marketing term for an office suite (bundled set of productivity applications), the first version of Office contained Microsoft Word, Microsoft Excel, and Microsoft PowerPoint. Over the years, Office applications have grown substantially closer with shared features such as a common spell checker, Object Linking and Embedding data integration and Visual Basic for Applications scripting language. Microsoft also positions Office as a development platform for line-of-business software under the Office Business Applications brand.
-0.93: On January 21, 2015, during the "Windows 10: The Next Chapter" press event, Microsoft unveiled Office for Windows 10, Windows Runtime ports of the Android and iOS versions of the Office Mobile suite. Optimized for smartphones and tablets, they are universal apps that can run on both Windows and Windows for phones, and share similar underlying code. A simplified version of Outlook was also added to the suite. They will be bundled with Windows 10 mobile devices, and available from the Windows Store for the PC version of Windows 10. Although the preview versions were free for most editing, the release versions will require an Office 365 subscription on larger tablets (screen size larger than 10.1 inches) and desktops for editing, as with large Android tablets. Smaller tablets and phones will have most editing features for free.
-0.87: In October 2022, Microsoft announced that it will phase out the Microsoft Office brand in favor of "Microsoft 365" by January 2023. The name will continue to be used for legacy product offerings.
-```
+ 0.99: Microsoft Office, or simply Office, is the former name of a family of client software, server software, and services developed by Microsoft. It was first announced by Bill Gates on August 1, 1988, at COMDEX in Las Vegas. Initially a marketing term for an office suite (bundled set of productivity applications), the first version of Office contained Microsoft Word, Microsoft Excel, and Microsoft PowerPoint. Over the years, Office applications have grown substantially closer with shared features such as a common spell checker, Object Linking and Embedding data integration and Visual Basic for Applications scripting language. Microsoft also positions Office as a development platform for line-of-business software under the Office Business Applications brand.
+ 0.93: On January 21, 2015, during the "Windows 10: The Next Chapter" press event, Microsoft unveiled Office for Windows 10, Windows Runtime ports of the Android and iOS versions of the Office Mobile suite. Optimized for smartphones and tablets, they are universal apps that can run on both Windows and Windows for phones, and share similar underlying code. A simplified version of Outlook was also added to the suite. They will be bundled with Windows 10 mobile devices, and available from the Windows Store for the PC version of Windows 10. Although the preview versions were free for most editing, the release versions will require an Office 365 subscription on larger tablets (screen size larger than 10.1 inches) and desktops for editing, as with large Android tablets. Smaller tablets and phones will have most editing features for free.
+ 0.87: In October 2022, Microsoft announced that it will phase out the Microsoft Office brand in favor of "Microsoft 365" by January 2023. The name will continue to be used for legacy product offerings.
+
## Another example - query and rerank
-```python PYTHON
+
+```python
+# Let's query the database
query = "What was the first youtube video about?"
+# create the query embedding
xq = co.embed(
texts=[query],
model='embed-english-v3.0',
@@ -245,37 +232,41 @@ xq = co.embed(
print(np.array(xq).shape)
+# query, returning the top 20 most similar results
res = idx.query(xq, top_k=20, include_metadata=True)
+# Look at the initial retrieval results
for match in res['matches']:
print(f"{match['score']:.2f}: {match['metadata']['text']}")
```
-```txt title="Output"
-(1, 1024)
-0.66: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
-0.58: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
-0.55: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
-0.55: According to a story that has often been repeated in the media, Hurley and Chen developed the idea for YouTube during the early months of 2005, after they had experienced difficulty sharing videos that had been shot at a dinner party at Chen's apartment in San Francisco. Karim did not attend the party and denied that it had occurred, but Chen remarked that the idea that YouTube was founded after a dinner party "was probably very strengthened by marketing ideas around creating a story that was very digestible".
-0.53: In December 2009, YouTube partnered with Vevo. In April 2010, Lady Gaga's "Bad Romance" became the most viewed video, becoming the first video to reach 200 million views on May 9, 2010.
-0.53: YouTube is a global online video sharing and social media platform headquartered in San Bruno, California. It was launched on February 14, 2005, by Steve Chen, Chad Hurley, and Jawed Karim. It is owned by Google, and is the second most visited website, after Google Search. YouTube has more than 2.5 billion monthly users who collectively watch more than one billion hours of videos each day. , videos were being uploaded at a rate of more than 500 hours of content per minute.
-0.53: YouTube has faced numerous challenges and criticisms in its attempts to deal with copyright, including the site's first viral video, Lazy Sunday, which had to be taken down, due to copyright concerns. At the time of uploading a video, YouTube users are shown a message asking them not to violate copyright laws. Despite this advice, many unauthorized clips of copyrighted material remain on YouTube. YouTube does not view videos before they are posted online, and it is left to copyright holders to issue a DMCA takedown notice pursuant to the terms of the Online Copyright Infringement Liability Limitation Act. Any successful complaint about copyright infringement results in a YouTube copyright strike. Three successful complaints for copyright infringement against a user account will result in the account and all of its uploaded videos being deleted. From 2007 to 2009 organizations including Viacom, Mediaset, and the English Premier League have filed lawsuits against YouTube, claiming that it has done too little to prevent the uploading of copyrighted material.
-0.51: Some YouTube videos have themselves had a direct effect on world events, such as "Innocence of Muslims" (2012) which spurred protests and related anti-American violence internationally. TED curator Chris Anderson described a phenomenon by which geographically distributed individuals in a certain field share their independently developed skills in YouTube videos, thus challenging others to improve their own skills, and spurring invention and evolution in that field. Journalist Virginia Heffernan stated in "The New York Times" that such videos have "surprising implications" for the dissemination of culture and even the future of classical music.
-0.50: Observing that face-to-face communication of the type that online videos convey has been "fine-tuned by millions of years of evolution," TED curator Chris Anderson referred to several YouTube contributors and asserted that "what Gutenberg did for writing, online video can now do for face-to-face communication." Anderson asserted that it is not far-fetched to say that online video will dramatically accelerate scientific advance, and that video contributors may be about to launch "the biggest learning cycle in human history." In education, for example, the Khan Academy grew from YouTube video tutoring sessions for founder Salman Khan's cousin into what "Forbes" Michael Noer called "the largest school in the world," with technology poised to disrupt how people learn. YouTube was awarded a 2008 George Foster Peabody Award, the website being described as a Speakers' Corner that "both embodies and promotes democracy." "The Washington Post" reported that a disproportionate share of YouTube's most subscribed channels feature minorities, contrasting with mainstream television in which the stars are largely white. A Pew Research Center study reported the development of "visual journalism," in which citizen eyewitnesses and established news organizations share in content creation. The study also concluded that YouTube was becoming an important platform by which people acquire news.
-0.50: YouTube was founded by Steve Chen, Chad Hurley, and Jawed Karim. The trio were early employees of PayPal, which left them enriched after the company was bought by eBay. Hurley had studied design at the Indiana University of Pennsylvania, and Chen and Karim studied computer science together at the University of Illinois Urbana-Champaign.
-0.49: In 2013, YouTube teamed up with satirical newspaper company "The Onion" to claim in an uploaded video that the video-sharing website was launched as a contest which had finally come to an end, and would shut down for ten years before being re-launched in 2023, featuring only the winning video. The video starred several YouTube celebrities, including Antoine Dodson. A video of two presenters announcing the nominated videos streamed live for 12 hours.
-0.48: Since its purchase by Google, YouTube has expanded beyond the core website into mobile apps, network television, and the ability to link with other platforms. Video categories on YouTube include music videos, video clips, news, short films, feature films, documentaries, audio recordings, movie trailers, teasers, live streams, vlogs, and more. Most content is generated by individuals, including collaborations between YouTubers and corporate sponsors. Established media corporations such as Disney, Paramount, and Warner Bros. Discovery have also created and expanded their corporate YouTube channels to advertise to a larger audience.
-0.47: YouTube has enabled people to more directly engage with government, such as in the CNN/YouTube presidential debates (2007) in which ordinary people submitted questions to U.S. presidential candidates via YouTube video, with a techPresident co-founder saying that Internet video was changing the political landscape. Describing the Arab Spring (2010–2012), sociologist Philip N. Howard quoted an activist's succinct description that organizing the political unrest involved using "Facebook to schedule the protests, Twitter to coordinate, and YouTube to tell the world." In 2012, more than a third of the U.S. Senate introduced a resolution condemning Joseph Kony 16 days after the "Kony 2012" video was posted to YouTube, with resolution co-sponsor Senator Lindsey Graham remarking that the video "will do more to lead to (Kony's) demise than all other action combined."
-0.47: YouTube carried out early experiments with live streaming, including a concert by U2 in 2009, and a question-and-answer session with US President Barack Obama in February 2010. These tests had relied on technology from 3rd-party partners, but in September 2010, YouTube began testing its own live streaming infrastructure. In April 2011, YouTube announced the rollout of "YouTube Live". The creation of live streams was initially limited to select partners. It was used for real-time broadcasting of events such as the 2012 Olympics in London. In October 2012, more than 8 million people watched Felix Baumgartner's jump from the edge of space as a live stream on YouTube.
-0.46: In June 2007, YouTube began trials of a system for automatic detection of uploaded videos that infringe copyright. Google CEO Eric Schmidt regarded this system as necessary for resolving lawsuits such as the one from Viacom, which alleged that YouTube profited from content that it did not have the right to distribute. The system, which was initially called "Video Identification" and later became known as Content ID, creates an ID File for copyrighted audio and video material, and stores it in a database. When a video is uploaded, it is checked against the database, and flags the video as a copyright violation if a match is found. When this occurs, the content owner has the choice of blocking the video to make it unviewable, tracking the viewing statistics of the video, or adding advertisements to the video.
-0.46: In January 2009, YouTube launched "YouTube for TV", a version of the website tailored for set-top boxes and other TV-based media devices with web browsers, initially allowing its videos to be viewed on the PlayStation 3 and Wii video game consoles.
-0.46: In September 2012, YouTube launched its first app for the iPhone, following the decision to drop YouTube as one of the preloaded apps in the iPhone 5 and iOS 6 operating system. According to GlobalWebIndex, YouTube was used by 35% of smartphone users between April and June 2013, making it the third-most used app.
-0.46: Conversely, YouTube has also allowed government to more easily engage with citizens, the White House's official YouTube channel being the seventh top news organization producer on YouTube in 2012 and in 2013 a healthcare exchange commissioned Obama impersonator Iman Crosson's YouTube music video spoof to encourage young Americans to enroll in the Affordable Care Act (Obamacare)-compliant health insurance. In February 2014, U.S. President Obama held a meeting at the White House with leading YouTube content creators to not only promote awareness of Obamacare but more generally to develop ways for government to better connect with the "YouTube Generation." Whereas YouTube's inherent ability to allow presidents to directly connect with average citizens was noted, the YouTube content creators' new media savvy was perceived necessary to better cope with the website's distracting content and fickle audience.
-0.46: Later that year, YouTube came under criticism for showing inappropriate videos targeted at children and often featuring popular characters in violent, sexual or otherwise disturbing situations, many of which appeared on YouTube Kids and attracted millions of views. The term "Elsagate" was coined on the Internet and then used by various news outlets to refer to this controversy. On November 11, 2017, YouTube announced it was strengthening site security to protect children from unsuitable content. Later that month, the company started to mass delete videos and channels that made improper use of family-friendly characters. As part of a broader concern regarding child safety on YouTube, the wave of deletions also targeted channels that showed children taking part in inappropriate or dangerous activities under the guidance of adults. Most notably, the company removed "Toy Freaks", a channel with over 8.5 million subscribers, that featured a father and his two daughters in odd and upsetting situations. According to analytics specialist SocialBlade, it earned up to £8.7 million annually prior to its deletion.
-0.45: In September 2020, YouTube announced that it would be launching a beta version of a new platform of 15-second videos, similar to TikTok, called YouTube Shorts. The platform was first tested in India but as of March 2021 has expanded to other countries including the United States with videos now able to be up to 1 minute long. The platform is not a standalone app, but is integrated into the main YouTube app. Like TikTok, it gives users access to built-in creative tools, including the possibility of adding licensed music to their videos. The platform had its global beta launch in July 2021.
-```
-
-```python PYTHON
+ (1, 1024)
+ 0.66: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
+ 0.58: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
+ 0.55: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
+ 0.55: According to a story that has often been repeated in the media, Hurley and Chen developed the idea for YouTube during the early months of 2005, after they had experienced difficulty sharing videos that had been shot at a dinner party at Chen's apartment in San Francisco. Karim did not attend the party and denied that it had occurred, but Chen remarked that the idea that YouTube was founded after a dinner party "was probably very strengthened by marketing ideas around creating a story that was very digestible".
+ 0.53: In December 2009, YouTube partnered with Vevo. In April 2010, Lady Gaga's "Bad Romance" became the most viewed video, becoming the first video to reach 200 million views on May 9, 2010.
+ 0.53: YouTube is a global online video sharing and social media platform headquartered in San Bruno, California. It was launched on February 14, 2005, by Steve Chen, Chad Hurley, and Jawed Karim. It is owned by Google, and is the second most visited website, after Google Search. YouTube has more than 2.5 billion monthly users who collectively watch more than one billion hours of videos each day. , videos were being uploaded at a rate of more than 500 hours of content per minute.
+ 0.53: YouTube has faced numerous challenges and criticisms in its attempts to deal with copyright, including the site's first viral video, Lazy Sunday, which had to be taken down, due to copyright concerns. At the time of uploading a video, YouTube users are shown a message asking them not to violate copyright laws. Despite this advice, many unauthorized clips of copyrighted material remain on YouTube. YouTube does not view videos before they are posted online, and it is left to copyright holders to issue a DMCA takedown notice pursuant to the terms of the Online Copyright Infringement Liability Limitation Act. Any successful complaint about copyright infringement results in a YouTube copyright strike. Three successful complaints for copyright infringement against a user account will result in the account and all of its uploaded videos being deleted. From 2007 to 2009 organizations including Viacom, Mediaset, and the English Premier League have filed lawsuits against YouTube, claiming that it has done too little to prevent the uploading of copyrighted material.
+ 0.51: Some YouTube videos have themselves had a direct effect on world events, such as "Innocence of Muslims" (2012) which spurred protests and related anti-American violence internationally. TED curator Chris Anderson described a phenomenon by which geographically distributed individuals in a certain field share their independently developed skills in YouTube videos, thus challenging others to improve their own skills, and spurring invention and evolution in that field. Journalist Virginia Heffernan stated in "The New York Times" that such videos have "surprising implications" for the dissemination of culture and even the future of classical music.
+ 0.50: Observing that face-to-face communication of the type that online videos convey has been "fine-tuned by millions of years of evolution," TED curator Chris Anderson referred to several YouTube contributors and asserted that "what Gutenberg did for writing, online video can now do for face-to-face communication." Anderson asserted that it is not far-fetched to say that online video will dramatically accelerate scientific advance, and that video contributors may be about to launch "the biggest learning cycle in human history." In education, for example, the Khan Academy grew from YouTube video tutoring sessions for founder Salman Khan's cousin into what "Forbes" Michael Noer called "the largest school in the world," with technology poised to disrupt how people learn. YouTube was awarded a 2008 George Foster Peabody Award, the website being described as a Speakers' Corner that "both embodies and promotes democracy." "The Washington Post" reported that a disproportionate share of YouTube's most subscribed channels feature minorities, contrasting with mainstream television in which the stars are largely white. A Pew Research Center study reported the development of "visual journalism," in which citizen eyewitnesses and established news organizations share in content creation. The study also concluded that YouTube was becoming an important platform by which people acquire news.
+ 0.50: YouTube was founded by Steve Chen, Chad Hurley, and Jawed Karim. The trio were early employees of PayPal, which left them enriched after the company was bought by eBay. Hurley had studied design at the Indiana University of Pennsylvania, and Chen and Karim studied computer science together at the University of Illinois Urbana-Champaign.
+ 0.49: In 2013, YouTube teamed up with satirical newspaper company "The Onion" to claim in an uploaded video that the video-sharing website was launched as a contest which had finally come to an end, and would shut down for ten years before being re-launched in 2023, featuring only the winning video. The video starred several YouTube celebrities, including Antoine Dodson. A video of two presenters announcing the nominated videos streamed live for 12 hours.
+ 0.48: Since its purchase by Google, YouTube has expanded beyond the core website into mobile apps, network television, and the ability to link with other platforms. Video categories on YouTube include music videos, video clips, news, short films, feature films, documentaries, audio recordings, movie trailers, teasers, live streams, vlogs, and more. Most content is generated by individuals, including collaborations between YouTubers and corporate sponsors. Established media corporations such as Disney, Paramount, and Warner Bros. Discovery have also created and expanded their corporate YouTube channels to advertise to a larger audience.
+ 0.47: YouTube has enabled people to more directly engage with government, such as in the CNN/YouTube presidential debates (2007) in which ordinary people submitted questions to U.S. presidential candidates via YouTube video, with a techPresident co-founder saying that Internet video was changing the political landscape. Describing the Arab Spring (2010–2012), sociologist Philip N. Howard quoted an activist's succinct description that organizing the political unrest involved using "Facebook to schedule the protests, Twitter to coordinate, and YouTube to tell the world." In 2012, more than a third of the U.S. Senate introduced a resolution condemning Joseph Kony 16 days after the "Kony 2012" video was posted to YouTube, with resolution co-sponsor Senator Lindsey Graham remarking that the video "will do more to lead to (Kony's) demise than all other action combined."
+ 0.47: YouTube carried out early experiments with live streaming, including a concert by U2 in 2009, and a question-and-answer session with US President Barack Obama in February 2010. These tests had relied on technology from 3rd-party partners, but in September 2010, YouTube began testing its own live streaming infrastructure. In April 2011, YouTube announced the rollout of "YouTube Live". The creation of live streams was initially limited to select partners. It was used for real-time broadcasting of events such as the 2012 Olympics in London. In October 2012, more than 8 million people watched Felix Baumgartner's jump from the edge of space as a live stream on YouTube.
+ 0.46: In June 2007, YouTube began trials of a system for automatic detection of uploaded videos that infringe copyright. Google CEO Eric Schmidt regarded this system as necessary for resolving lawsuits such as the one from Viacom, which alleged that YouTube profited from content that it did not have the right to distribute. The system, which was initially called "Video Identification" and later became known as Content ID, creates an ID File for copyrighted audio and video material, and stores it in a database. When a video is uploaded, it is checked against the database, and flags the video as a copyright violation if a match is found. When this occurs, the content owner has the choice of blocking the video to make it unviewable, tracking the viewing statistics of the video, or adding advertisements to the video.
+ 0.46: In January 2009, YouTube launched "YouTube for TV", a version of the website tailored for set-top boxes and other TV-based media devices with web browsers, initially allowing its videos to be viewed on the PlayStation 3 and Wii video game consoles.
+ 0.46: In September 2012, YouTube launched its first app for the iPhone, following the decision to drop YouTube as one of the preloaded apps in the iPhone 5 and iOS 6 operating system. According to GlobalWebIndex, YouTube was used by 35% of smartphone users between April and June 2013, making it the third-most used app.
+ 0.46: Conversely, YouTube has also allowed government to more easily engage with citizens, the White House's official YouTube channel being the seventh top news organization producer on YouTube in 2012 and in 2013 a healthcare exchange commissioned Obama impersonator Iman Crosson's YouTube music video spoof to encourage young Americans to enroll in the Affordable Care Act (Obamacare)-compliant health insurance. In February 2014, U.S. President Obama held a meeting at the White House with leading YouTube content creators to not only promote awareness of Obamacare but more generally to develop ways for government to better connect with the "YouTube Generation." Whereas YouTube's inherent ability to allow presidents to directly connect with average citizens was noted, the YouTube content creators' new media savvy was perceived necessary to better cope with the website's distracting content and fickle audience.
+ 0.46: Later that year, YouTube came under criticism for showing inappropriate videos targeted at children and often featuring popular characters in violent, sexual or otherwise disturbing situations, many of which appeared on YouTube Kids and attracted millions of views. The term "Elsagate" was coined on the Internet and then used by various news outlets to refer to this controversy. On November 11, 2017, YouTube announced it was strengthening site security to protect children from unsuitable content. Later that month, the company started to mass delete videos and channels that made improper use of family-friendly characters. As part of a broader concern regarding child safety on YouTube, the wave of deletions also targeted channels that showed children taking part in inappropriate or dangerous activities under the guidance of adults. Most notably, the company removed "Toy Freaks", a channel with over 8.5 million subscribers, that featured a father and his two daughters in odd and upsetting situations. According to analytics specialist SocialBlade, it earned up to £8.7 million annually prior to its deletion.
+ 0.45: In September 2020, YouTube announced that it would be launching a beta version of a new platform of 15-second videos, similar to TikTok, called YouTube Shorts. The platform was first tested in India but as of March 2021 has expanded to other countries including the United States with videos now able to be up to 1 minute long. The platform is not a standalone app, but is integrated into the main YouTube app. Like TikTok, it gives users access to built-in creative tools, including the possibility of adding licensed music to their videos. The platform had its global beta launch in July 2021.
+
+
+
+```python
+# Add Cohere Reranking Step
+# embeds=[np.float32(data_array[i]['embedding']) for i in range(len(data_array))]
docs =[match['metadata']['text'] for match in res['matches']]
rerank_response = co.rerank(
@@ -288,8 +279,7 @@ for response in rerank_response:
print(f"{response.relevance_score:.2f}: {response.document['text']}")
```
-```txt title="Output"
-0.95: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
-0.92: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
-0.91: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
-```
+ 0.95: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
+ 0.92: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
+ 0.91: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
+
diff --git a/fern/pages/cookbooks/embed-jobs.mdx b/fern/pages/cookbooks/embed-jobs.mdx
index f91142a22..b25e8b484 100644
--- a/fern/pages/cookbooks/embed-jobs.mdx
+++ b/fern/pages/cookbooks/embed-jobs.mdx
@@ -3,16 +3,26 @@ title: Semantic Search with Cohere Embed Jobs
slug: /page/embed-jobs
description: "This page contains a basic tutorial on how to use Cohere's Embed Jobs functionality."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, embed jobs"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-```python PYTHON
+
+
+
+
+
+```python
+# TODO: upgrade to "cohere>5"
+! pip install "cohere<5" hnswlib -q
+```
+
+
+```python
import time
import cohere
import hnswlib
@@ -21,7 +31,10 @@ co = cohere.Client('COHERE_API_KEY')
## Step 1: Upload a dataset
-```python PYTHON
+
+```python
+# Upload a dataset for embed jobs
+# This sample dataset has wikipedia articles on the following: Youtube, United States, United Kingdom, Elizabeth II, Wikipedia, 2022 FIFA World Cup, Microsoft Office, India, Christiano Ronaldo, Cleopatra, Instagram, Facebook, and Ukraine
dataset_file_path = "data/embed_jobs_sample_data.jsonl" # Full path - https://raw.githubusercontent.com/cohere-ai/cohere-developer-experience/main/notebooks/data/embed_jobs_sample_data.jsonl
@@ -33,84 +46,52 @@ ds=co.create_dataset(
)
```
-```txt title="Output"
-uploading file, starting validation...
-sample-file-hca4x0 was uploaded
-...
-```
+ uploading file, starting validation...
+ sample-file-hca4x0 was uploaded
+ ...
-```python PYTHON
-print(ds.await_validation())
-```
-```txt title="Output"
-cohere.Dataset {
- id: sample-file-hca4x0
- name: sample_file
- dataset_type: embed-input
- validation_status: validated
- created_at: 2024-01-13 02:51:48.215973
- updated_at: 2024-01-13 02:51:48.215973
- download_urls: ['']
- validation_error: None
- validation_warnings: []
-}
+
+```python
+print(ds.await_validation())
```
## Step 2: Create embeddings via Cohere's Embed Jobs endpoint
-```python PYTHON
+
+```python
+# Dataset has been uploaded, create an embed job and specify the input type as "search document" since this will live in your Pinecone DB
job = co.create_embed_job(
dataset_id=ds.id,
input_type='search_document' ,
- model='embed-english-v3.0',
+ model='embed-english-v3.0',
embeddings_types=['float'])
-job.wait() # poll the server until the job is completed
+job.wait() # poll the server until the job is completed
```
-```txt title="Output"
-...
-...
-```
+ ...
+ ...
+
-```python PYTHON
-print(job)
-```
-```txt title="Output"
-cohere.EmbedJob {
- job_id: 792bbc1a-561b-48c2-8a97-0c80c1914ea8
- status: complete
- created_at: 2024-01-13T02:53:31.879719Z
- input_dataset_id: sample-file-hca4x0
- output_urls: None
- model: embed-english-v3.0
- truncate: RIGHT
- percent_complete: 100
- output: cohere.Dataset {
- id: embeded-sample-file-drtjf9
- name: embeded-sample-file
- dataset_type: embed-result
- validation_status: validated
- created_at: 2024-01-13 02:53:33.569362
- updated_at: 2024-01-13 02:53:33.569362
- download_urls: ['']
- validation_error: None
- validation_warnings: []
-}
-}
+```python
+print(job)
```
## Step 3: Download and prepare the embeddings
-```python PYTHON
+
+```python
+# Save down the output of the job
embeddings_file_path = 'embed_jobs_output.csv'
output_dataset=co.get_dataset(job.output.id)
output_dataset.save(filepath=embeddings_file_path, format="csv")
```
-```python PYTHON
+
+```python
+# Add the results
embeddings=[]
texts=[]
for record in output_dataset:
@@ -120,7 +101,9 @@ for record in output_dataset:
## Step 4: Initialize Hnwslib index and add embeddings
-```python PYTHON
+
+```python
+# Create the hnsw index
index = hnswlib.Index(space='ip', dim=1024)
index.init_index(max_elements=len(embeddings), ef_construction=512, M=64)
index.add_items(embeddings,list(range(len(embeddings))))
@@ -128,15 +111,20 @@ index.add_items(embeddings,list(range(len(embeddings))))
## Step 5: Query the index and rerank the results
-```python PYTHON
+
+```python
+# Query the Database
query = "What was the first youtube video about?"
+# Convert the query into embeddings
query_emb=co.embed(
texts=[query], model="embed-english-v3.0", input_type="search_query"
).embeddings
+# Retrieve the initial results from your vector db
doc_index = index.knn_query(query_emb, k=10)[0][0]
+# From the doc_index, get the text from each index and then pass the text into rerank
docs_to_rerank = []
for index in doc_index:
docs_to_rerank.append(texts[index])
@@ -150,7 +138,9 @@ final_result = co.rerank(
## Step 6: Display the results
-```python PYTHON
+
+```python
+# Output Results
for idx, r in enumerate(final_result):
print(f"Document Rank: {idx + 1}, Document Index: {r.index}")
print(f"Document: {r.document['text']}")
@@ -158,18 +148,19 @@ for idx, r in enumerate(final_result):
print("\n")
```
-```txt title="Output"
-Document Rank: 1, Document Index: 0
-Document: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
-Relevance Score: 0.94815
-
+ Document Rank: 1, Document Index: 0
+ Document: YouTube began as a venture capital–funded technology startup. Between November 2005 and April 2006, the company raised money from various investors, with Sequoia Capital, $11.5 million, and Artis Capital Management, $8 million, being the largest two. YouTube's early headquarters were situated above a pizzeria and a Japanese restaurant in San Mateo, California. In February 2005, the company activated codice_1. The first video was uploaded April 23, 2005. Titled "Me at the zoo", it shows co-founder Jawed Karim at the San Diego Zoo and can still be viewed on the site. In May, the company launched a public beta and by November, a Nike ad featuring Ronaldinho became the first video to reach one million total views. The site launched officially on December 15, 2005, by which time the site was receiving 8 million views a day. Clips at the time were limited to 100 megabytes, as little as 30 seconds of footage.
+ Relevance Score: 0.94815
+
+
+ Document Rank: 2, Document Index: 1
+ Document: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
+ Relevance Score: 0.91626
+
+
+ Document Rank: 3, Document Index: 2
+ Document: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
+ Relevance Score: 0.90665
+
+
-Document Rank: 2, Document Index: 1
-Document: Karim said the inspiration for YouTube first came from the Super Bowl XXXVIII halftime show controversy when Janet Jackson's breast was briefly exposed by Justin Timberlake during the halftime show. Karim could not easily find video clips of the incident and the 2004 Indian Ocean Tsunami online, which led to the idea of a video-sharing site. Hurley and Chen said that the original idea for YouTube was a video version of an online dating service, and had been influenced by the website Hot or Not. They created posts on Craigslist asking attractive women to upload videos of themselves to YouTube in exchange for a $100 reward. Difficulty in finding enough dating videos led to a change of plans, with the site's founders deciding to accept uploads of any video.
-Relevance Score: 0.91626
-
-
-Document Rank: 3, Document Index: 2
-Document: YouTube was not the first video-sharing site on the Internet; Vimeo was launched in November 2004, though that site remained a side project of its developers from CollegeHumor at the time and did not grow much, either. The week of YouTube's launch, NBC-Universal's "Saturday Night Live" ran a skit "Lazy Sunday" by The Lonely Island. Besides helping to bolster ratings and long-term viewership for "Saturday Night Live", "Lazy Sunday"'s status as an early viral video helped establish YouTube as an important website. Unofficial uploads of the skit to YouTube drew in more than five million collective views by February 2006 before they were removed when NBCUniversal requested it two months later based on copyright concerns. Despite eventually being taken down, these duplicate uploads of the skit helped popularize YouTube's reach and led to the upload of more third-party content. The site grew rapidly; in July 2006, the company announced that more than 65,000 new videos were being uploaded every day and that the site was receiving 100 million video views per day.
-Relevance Score: 0.90665
-```
diff --git a/fern/pages/cookbooks/fueling-generative-content.mdx b/fern/pages/cookbooks/fueling-generative-content.mdx
index 1f3337351..e33ef096f 100644
--- a/fern/pages/cookbooks/fueling-generative-content.mdx
+++ b/fern/pages/cookbooks/fueling-generative-content.mdx
@@ -3,24 +3,34 @@ title: Fueling Generative Content with Keyword Research
slug: /page/fueling-generative-content
description: "This page contains a basic workflow for using Cohere's models to come up with keyword content ideas."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, LLMs, text generation, AI for marketing"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
+
+
+
+
Generative models have proven extremely useful in content idea generation. But they don’t take into account user search demand and trends. In this notebook, let’s see how we can solve that by adding keyword research into the equation.
-Read the accompanying [blog post here](https://cohere.com/blog/generative-content-keyword-research/).
+Read the accompanying [blog post here](https://txt.cohere.ai/generative-content-keyword-research/).
+
-```python PYTHON
+```python
+# Install packages
! pip install cohere -q
```
-```python PYTHON
+
+```python
import cohere
import numpy as np
import pandas as pd
@@ -30,75 +40,139 @@ import cohere
co = cohere.Client("COHERE_API_KEY") # Get your API key: https://dashboard.cohere.com/api-keys
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
#@title Enable text wrapping in Google Colab
from IPython.display import HTML, display
def set_css():
display(HTML('''
-
+
'''))
get_ipython().events.register('pre_run_cell', set_css)
```
+# Step 1: Get a list of High-performing Keywords
+
First, we need to get a supply of high-traffic keywords for a given topic. We can get this via keyword research tools, of which are many available. We’ll use Google Keyword Planner, which is free to use.
-```python PYTHON
+
+```python
+# Download the pre-created dataset (feel free to replace with your CSV file, containing two columns - "keyword" and "volume")
import wget
wget.download("https://raw.githubusercontent.com/cohere-ai/cohere-developer-experience/main/notebooks/data/remote_teams.csv", "remote_teams.csv")
```
-```
-'remote_teams.csv'
-```
-```python PYTHON
+
+
+
+
+
+
+
+
+ 'remote_teams.csv'
+
+
+
+
+```python
+# Create a dataframe
df = pd.read_csv('remote_teams.csv')
df.columns = ["keyword","volume"]
df.head()
```
+
+
+
+
+
+
+
+
+
-
-
-
- |
- keyword |
- volume |
-
-
-
-
- 0 |
- managing remote teams |
- 1000 |
-
-
- 1 |
- remote teams |
- 390 |
-
-
- 2 |
- collaboration tools for remote teams |
- 320 |
-
-
- 3 |
- online games for remote teams |
- 320 |
-
-
- 4 |
- how to manage remote teams |
- 260 |
-
-
-
+
+
+
+
+ |
+ keyword |
+ volume |
+
+
+
+
+ 0 |
+ managing remote teams |
+ 1000 |
+
+
+ 1 |
+ remote teams |
+ 390 |
+
+
+ 2 |
+ collaboration tools for remote teams |
+ 320 |
+
+
+ 3 |
+ online games for remote teams |
+ 320 |
+
+
+ 4 |
+ how to manage remote teams |
+ 260 |
+
+
+
+
+
+# Step 2: Group the Keywords into Topics
+
We now have a list of keywords, but this list is still raw. For example, “managing remote teams” is the top-ranking keyword in this list. But at the same time, there are many similar keywords further down in the list, such as “how to effectively manage remote teams.”
We can do that by clustering them into topics. For this, we’ll leverage Cohere’s Embed endpoint and scikit-learn.
@@ -107,7 +181,8 @@ We can do that by clustering them into topics. For this, we’ll leverage Cohere
The Cohere Embed endpoint turns a text input into a text embedding.
-```python PYTHON
+
+```python
def embed_text(texts):
output = co.embed(
texts=texts,
@@ -119,173 +194,285 @@ def embed_text(texts):
embeds = np.array(embed_text(df['keyword'].tolist()))
```
+
+
+
+
+
+
### Cluster the Keywords into Topics with scikit-learn
We then use these embeddings to cluster the keywords. A common term used for this exercise is “topic modeling.” Here, we can leverage scikit-learn’s KMeans module, a machine learning algorithm for clustering.
-```python PYTHON
+
+```python
NUM_TOPICS = 4
kmeans = KMeans(n_clusters=NUM_TOPICS, random_state=21, n_init="auto").fit(embeds)
df['topic'] = list(kmeans.labels_)
df.head()
```
+
+
+
+
+
+
+
+
+
-
-
-
- |
- keyword |
- volume |
- topic |
-
-
-
-
- 0 |
- managing remote teams |
- 1000 |
- 0 |
-
-
- 1 |
- remote teams |
- 390 |
- 1 |
-
-
- 2 |
- collaboration tools for remote teams |
- 320 |
- 1 |
-
-
- 3 |
- online games for remote teams |
- 320 |
- 3 |
-
-
- 4 |
- how to manage remote teams |
- 260 |
- 0 |
-
-
-
+
+
+
+
+ |
+ keyword |
+ volume |
+ topic |
+
+
+
+
+ 0 |
+ managing remote teams |
+ 1000 |
+ 0 |
+
+
+ 1 |
+ remote teams |
+ 390 |
+ 1 |
+
+
+ 2 |
+ collaboration tools for remote teams |
+ 320 |
+ 1 |
+
+
+ 3 |
+ online games for remote teams |
+ 320 |
+ 3 |
+
+
+ 4 |
+ how to manage remote teams |
+ 260 |
+ 0 |
+
+
+
+
+
### Generate Topic Names with Cohere Chat
We use the Chat to generate a topic name for that cluster.
-```python PYTHON
+
+```python
+# Group the DataFrame by 'topic' and aggregate the 'keyword' column into sets (which automatically removes duplicates)
topic_keywords_dict = {topic: list(set(group['keyword'])) for topic, group in df.groupby('topic')}
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
+# Function to generate a topic name based on keywords
def generate_topic_name(keywords):
# Construct the prompt
prompt = f"""Generate a concise topic name that best represents these keywords.\
Provide just the topic name and not any additional details.
Keywords: {', '.join(keywords)}"""
-
+
# Call the Cohere API
response = co.chat(
model='command-r', # Choose the model size
message=prompt,
preamble="")
-
+
# Return the generated text
return response.text
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
+# Generate topic names and create a mapping of topic number to topic name
topic_name_mapping = {topic: generate_topic_name(keywords) for topic, keywords in topic_keywords_dict.items()}
+# Use the mapping to create a new column in the DataFrame
df['topic_name'] = df['topic'].map(topic_name_mapping)
+# Display the first few rows to verify the new column
df.head()
```
+
+
+
+
+
+
+
+
+
-
-
-
- |
- keyword |
- volume |
- topic |
- topic_name |
-
-
-
-
- 0 |
- managing remote teams |
- 1000 |
- 0 |
- Remote Team Management |
-
-
- 1 |
- remote teams |
- 390 |
- 1 |
- Remote Team Tools and Tips |
-
-
- 2 |
- collaboration tools for remote teams |
- 320 |
- 1 |
- Remote Team Tools and Tips |
-
-
- 3 |
- online games for remote teams |
- 320 |
- 3 |
- Remote Team Fun |
-
-
- 4 |
- how to manage remote teams |
- 260 |
- 0 |
- Remote Team Management |
-
-
-
+
+
+
+
+ |
+ keyword |
+ volume |
+ topic |
+ topic_name |
+
+
+
+
+ 0 |
+ managing remote teams |
+ 1000 |
+ 0 |
+ Remote Team Management |
+
+
+ 1 |
+ remote teams |
+ 390 |
+ 1 |
+ Remote Team Tools and Tips |
+
+
+ 2 |
+ collaboration tools for remote teams |
+ 320 |
+ 1 |
+ Remote Team Tools and Tips |
+
+
+ 3 |
+ online games for remote teams |
+ 320 |
+ 3 |
+ Remote Team Fun |
+
+
+ 4 |
+ how to manage remote teams |
+ 260 |
+ 0 |
+ Remote Team Management |
+
+
+
-```python PYTHON
+
+
+
+```python
+# View the list of topics
for topic, name in topic_name_mapping.items():
print(f"Topic {topic}: {name}")
```
-```
-Topic 0: Remote Team Management
-Topic 1: Remote Team Tools and Tips
-Topic 2: Remote Team Resources
-Topic 3: Remote Team Fun
-```
+
+
+
+
+
+
+ Topic 0: Remote Team Management
+ Topic 1: Remote Team Tools and Tips
+ Topic 2: Remote Team Resources
+ Topic 3: Remote Team Fun
+
+
+# Step 3: Generate Blog Post Ideas for Each Topic
Now that we have the keywords nicely grouped into topics, we can proceed to generate the content ideas.
+
### Take the Top Keywords from Each Topic
Here we can implement a filter to take just the top N keywords from each topic, sorted by the search volume. In our case, we use 10.
-```python PYTHON
+
+```python
TOP_N = 10
+# Group the DataFrame by topic and select the top N keywords sorted by volume
top_keywords = (df.groupby('topic')
.apply(lambda x: x.nlargest(TOP_N, 'volume'))
.reset_index(drop=True))
+# Convert the DataFrame to a nested dictionary
content_by_topic = {}
for topic, group in top_keywords.groupby('topic'):
keywords = ', '.join(list(group['keyword']))
@@ -294,34 +481,60 @@ for topic, group in top_keywords.groupby('topic'):
content_by_topic[topic] = {'topic_name': topic_name, 'keywords': keywords}
```
-```python PYTHON
+
+
+
+
+
+
+
+```python
+# Print the topics and they top keywords
content_by_topic
```
-```
-{0: {'topic_name': 'Remote Team Management',
- 'keywords': 'managing remote teams, how to manage remote teams, leading remote teams, managing remote teams best practices, remote teams best practices, best practices for managing remote teams, manage remote teams, building culture in remote teams, culture building for remote teams, managing remote teams training'},
- 1: {'topic_name': 'Remote Team Tools and Tips',
- 'keywords': 'remote teams, collaboration tools for remote teams, team building for remote teams, scrum remote teams, tools for remote teams, zapier remote teams, working agreements for remote teams, working with remote teams, free collaboration tools for remote teams, free retrospective tools for remote teams'},
- 2: {'topic_name': 'Remote Team Resources',
- 'keywords': 'best collaboration tools for remote teams, slack best practices for remote teams, best communication tools for remote teams, best tools for remote teams, always on video for remote teams, best apps for remote teams, best free collaboration tools for remote teams, best games for remote teams, best gifts for remote teams, best ice breaker questions for remote teams'},
- 3: {'topic_name': 'Remote Team Fun',
- 'keywords': 'online games for remote teams, team building activities for remote teams, games for remote teams, retrospective ideas for remote teams, team building ideas for remote teams, fun retrospective ideas for remote teams, retro ideas for remote teams, team building exercises for remote teams, trust building exercises for remote teams, activities for remote teams'}}
-```
+
+
+
+
+
+
+
+
+
+ {0: {'topic_name': 'Remote Team Management',
+ 'keywords': 'managing remote teams, how to manage remote teams, leading remote teams, managing remote teams best practices, remote teams best practices, best practices for managing remote teams, manage remote teams, building culture in remote teams, culture building for remote teams, managing remote teams training'},
+ 1: {'topic_name': 'Remote Team Tools and Tips',
+ 'keywords': 'remote teams, collaboration tools for remote teams, team building for remote teams, scrum remote teams, tools for remote teams, zapier remote teams, working agreements for remote teams, working with remote teams, free collaboration tools for remote teams, free retrospective tools for remote teams'},
+ 2: {'topic_name': 'Remote Team Resources',
+ 'keywords': 'best collaboration tools for remote teams, slack best practices for remote teams, best communication tools for remote teams, best tools for remote teams, always on video for remote teams, best apps for remote teams, best free collaboration tools for remote teams, best games for remote teams, best gifts for remote teams, best ice breaker questions for remote teams'},
+ 3: {'topic_name': 'Remote Team Fun',
+ 'keywords': 'online games for remote teams, team building activities for remote teams, games for remote teams, retrospective ideas for remote teams, team building ideas for remote teams, fun retrospective ideas for remote teams, retro ideas for remote teams, team building exercises for remote teams, trust building exercises for remote teams, activities for remote teams'}}
+
+
### Create a Prompt with These Keywords
Next, we use the Chat endpoint to produce the content ideas. The prompt we’ll use is as follows
-```python PYTHON
+
+```python
def generate_blog_ideas(keywords):
- prompt = f"""{keywords}\n\nThe above is a list of high-traffic keywords obtained from a keyword research tool.
-Suggest three blog post ideas that are highly relevant to these keywords.
-For each idea, write a one paragraph abstract about the topic.
+ prompt = f"""{keywords}\n\nThe above is a list of high-traffic keywords obtained from a keyword research tool.
+Suggest three blog post ideas that are highly relevant to these keywords.
+For each idea, write a one paragraph abstract about the topic.
Use this format:
Blog title:
Abstract: """
-
+
response = co.chat(
model='command-r',
message = prompt)
@@ -329,15 +542,28 @@ Abstract: """
```
+
+
+
+
+
+
### Generate Content Ideas
Next, we generate the blog post ideas. It takes in a string of keywords, calls the Chat endpoint, and returns the generated text.
-```python PYTHON
+
+```python
+# Generate content ideas
for key,value in content_by_topic.items():
value['ideas'] = generate_blog_ideas(value['keywords'])
+# Print the results
for key,value in content_by_topic.items():
print(f"Topic Name: {value['topic_name']}\n")
print(f"Top Keywords: {value['keywords']}\n")
@@ -345,65 +571,79 @@ for key,value in content_by_topic.items():
print("-"*50)
```
-```
-Topic Name: Remote Team Management
-
-Top Keywords: managing remote teams, how to manage remote teams, leading remote teams, managing remote teams best practices, remote teams best practices, best practices for managing remote teams, manage remote teams, building culture in remote teams, culture building for remote teams, managing remote teams training
-
-Blog Post Ideas: Here are three blog post ideas:
-
-1. Blog title: "Leading Remote Teams: Strategies for Effective Management"
- Abstract: Effective management of remote teams is crucial for success, but it comes with unique challenges. This blog will explore practical strategies for leading dispersed employees, focusing on building a cohesive and productive virtual workforce. It will cover topics such as establishing clear communication protocols, fostering a collaborative environment, and the importance of trusting and empowering your remote employees for enhanced performance.
-
-2. Blog title: "Remote Teams' Best Practices: Creating a Vibrant and Engaging Culture"
- Abstract: Building a rich culture in a remote team setting is essential for employee engagement and retention. The blog will delve into creative ways to foster a sense of community and connection among team members who may be scattered across the globe. It will offer practical tips on creating virtual rituals, fostering open communication, and harnessing the power of technology for cultural development, ensuring remote employees feel valued and engaged.
-
-3. Blog title: "Managing Remote Teams: A Comprehensive Guide to Training and Development"
- Abstract: Training and developing remote teams present specific challenges and opportunities. This comprehensive guide will arm managers with techniques to enhance their remote team's skills and knowledge. It will explore the latest tools and methodologies for remote training, including virtual workshops, e-learning platforms, and performance coaching. Additionally, the blog will discuss the significance of ongoing development and how to create an environment that encourages self-improvement and learning.
-
-Each of these topics explores a specific aspect of managing remote teams, providing valuable insights and practical guidance for leaders and managers in the evolving remote work landscape.
-
---------------------------------------------------
-Topic Name: Remote Team Tools and Tips
-
-Top Keywords: remote teams, collaboration tools for remote teams, team building for remote teams, scrum remote teams, tools for remote teams, zapier remote teams, working agreements for remote teams, working with remote teams, free collaboration tools for remote teams, free retrospective tools for remote teams
-
-Blog Post Ideas: 1. Blog title: "The Ultimate Guide to Building Effective Remote Teams"
- Abstract: Building a cohesive and productive remote team can be challenging. This blog will serve as a comprehensive guide, offering practical tips and insights on how to create a united and successful virtual workforce. It will cover essential topics such as building a strong team culture, utilizing collaboration tools, and fostering effective communication strategies, ensuring remote teams can thrive and achieve their full potential.
-
-2. Blog title: "The Best Collaboration Tools for Remote Teams: A Comprehensive Review"
- Abstract: With the rapid rise of remote work, collaboration tools have become essential for teams' productivity and efficiency. This blog aims to review and compare the most popular collaboration tools, providing an in-depth analysis of their features, ease of use, and benefits. It will offer insights into choosing the right tools for remote collaboration, helping teams streamline their workflows and enhance their overall performance.
-
-3. Blog title: "Remote Retrospective: A Guide to Reflect and Grow as a Remote Team"
- Abstract: Conducting effective retrospectives is crucial for remote teams to reflect on their experiences, learn from the past, and chart a course for the future. This blog will focus on remote retrospectives, exploring different formats, techniques, and free tools that teams can use to foster continuous improvement. It will also provide tips on creating a safe and inclusive environment, encouraging honest feedback and productive discussions.
-
---------------------------------------------------
-Topic Name: Remote Team Resources
-
-Top Keywords: best collaboration tools for remote teams, slack best practices for remote teams, best communication tools for remote teams, best tools for remote teams, always on video for remote teams, best apps for remote teams, best free collaboration tools for remote teams, best games for remote teams, best gifts for remote teams, best ice breaker questions for remote teams
-
-Blog Post Ideas: 1. Blog title: "The Ultimate Guide to Remote Team Collaboration Tools"
- Abstract: With the rise of remote work, choosing the right collaboration tools can be crucial to a team's success and productivity. This blog aims to be an comprehensive guide, outlining the various types of tools available, from communication platforms like Slack to project management software and online collaboration tools. It will offer best practices and guidelines for selecting and utilizing these tools, ensuring remote teams can work seamlessly together and maximize their output.
-
-2. Blog title: "Remote Team Management: Tips for Leading a Successful Virtual Workforce"
- Abstract: Managing a remote team comes with its own set of challenges. This blog will provide an in-depth exploration of best practices for leading and motivating virtual teams. Covering topics such as effective communication strategies, performance evaluation, and maintaining a cohesive team culture, it will offer practical tips for managers and leaders to ensure their remote teams are engaged, productive, and well-managed.
-
-3. Blog title: "The Fun Side of Remote Work: Games, Icebreakers, and Team Building Activities"
- Abstract: Remote work can be isolating, and this blog aims to provide some fun and creative solutions. It will offer a comprehensive guide to the best online games, icebreaker questions, and virtual team building activities that remote teams can use to connect and bond. From virtual escape rooms to interactive games and thought-provoking icebreakers, these ideas will help enhance team spirit, foster collaboration, and create a enjoyable remote work experience.
-
---------------------------------------------------
-Topic Name: Remote Team Fun
-
-Top Keywords: online games for remote teams, team building activities for remote teams, games for remote teams, retrospective ideas for remote teams, team building ideas for remote teams, fun retrospective ideas for remote teams, retro ideas for remote teams, team building exercises for remote teams, trust building exercises for remote teams, activities for remote teams
-
-Blog Post Ideas: 1. Blog title: "The Great Remote Retro: Fun Games and Activities for Your Team"
- Abstract: Remote work can make team building challenging. This blog post will be a fun guide to hosting interactive retro games and activities that bring your remote team together. From online escape rooms to virtual scavenger hunts, we'll explore the best ways to engage and unite your team, fostering collaboration and camaraderie. Virtual icebreakers and retrospective ideas will also be included to make your remote meetings more interactive and enjoyable.
-2. Blog title: "Trust Falls: Building Trust Among Remote Teams"
- Abstract: Trust is the foundation of every successful team, but how do you build it when everyone is scattered across different locations? This blog will focus on trust-building exercises and activities designed specifically for remote teams. From virtual trust falls to transparent communication practices, we'll discover innovative ways to strengthen team bonds and foster a culture of trust. You'll learn how to create an environment where your remote team can thrive and collaborate effectively.
-3. Blog title: "Game Night for Remote Teams: A Guide to Online Games and Activities"
- Abstract: Miss the old office game nights? This blog will bring the fun back with a guide to hosting online game nights and activities that are perfect for remote teams. From trivia games to virtual board games and even remote-friendly outdoor adventures, we'll keep your team engaged and entertained. With tips on setting up online tournaments and ideas for encouraging participation, your virtual game nights will be the highlight of your team's week. Keep your remote team spirit high!
+
+
+
+
+ Topic Name: Remote Team Management
+
+ Top Keywords: managing remote teams, how to manage remote teams, leading remote teams, managing remote teams best practices, remote teams best practices, best practices for managing remote teams, manage remote teams, building culture in remote teams, culture building for remote teams, managing remote teams training
+
+ Blog Post Ideas: Here are three blog post ideas:
+
+ 1. Blog title: "Leading Remote Teams: Strategies for Effective Management"
+ Abstract: Effective management of remote teams is crucial for success, but it comes with unique challenges. This blog will explore practical strategies for leading dispersed employees, focusing on building a cohesive and productive virtual workforce. It will cover topics such as establishing clear communication protocols, fostering a collaborative environment, and the importance of trusting and empowering your remote employees for enhanced performance.
+
+ 2. Blog title: "Remote Teams' Best Practices: Creating a Vibrant and Engaging Culture"
+ Abstract: Building a rich culture in a remote team setting is essential for employee engagement and retention. The blog will delve into creative ways to foster a sense of community and connection among team members who may be scattered across the globe. It will offer practical tips on creating virtual rituals, fostering open communication, and harnessing the power of technology for cultural development, ensuring remote employees feel valued and engaged.
+
+ 3. Blog title: "Managing Remote Teams: A Comprehensive Guide to Training and Development"
+ Abstract: Training and developing remote teams present specific challenges and opportunities. This comprehensive guide will arm managers with techniques to enhance their remote team's skills and knowledge. It will explore the latest tools and methodologies for remote training, including virtual workshops, e-learning platforms, and performance coaching. Additionally, the blog will discuss the significance of ongoing development and how to create an environment that encourages self-improvement and learning.
+
+ Each of these topics explores a specific aspect of managing remote teams, providing valuable insights and practical guidance for leaders and managers in the evolving remote work landscape.
+
+ --------------------------------------------------
+ Topic Name: Remote Team Tools and Tips
+
+ Top Keywords: remote teams, collaboration tools for remote teams, team building for remote teams, scrum remote teams, tools for remote teams, zapier remote teams, working agreements for remote teams, working with remote teams, free collaboration tools for remote teams, free retrospective tools for remote teams
+
+ Blog Post Ideas: 1. Blog title: "The Ultimate Guide to Building Effective Remote Teams"
+ Abstract: Building a cohesive and productive remote team can be challenging. This blog will serve as a comprehensive guide, offering practical tips and insights on how to create a united and successful virtual workforce. It will cover essential topics such as building a strong team culture, utilizing collaboration tools, and fostering effective communication strategies, ensuring remote teams can thrive and achieve their full potential.
+
+ 2. Blog title: "The Best Collaboration Tools for Remote Teams: A Comprehensive Review"
+ Abstract: With the rapid rise of remote work, collaboration tools have become essential for teams' productivity and efficiency. This blog aims to review and compare the most popular collaboration tools, providing an in-depth analysis of their features, ease of use, and benefits. It will offer insights into choosing the right tools for remote collaboration, helping teams streamline their workflows and enhance their overall performance.
+
+ 3. Blog title: "Remote Retrospective: A Guide to Reflect and Grow as a Remote Team"
+ Abstract: Conducting effective retrospectives is crucial for remote teams to reflect on their experiences, learn from the past, and chart a course for the future. This blog will focus on remote retrospectives, exploring different formats, techniques, and free tools that teams can use to foster continuous improvement. It will also provide tips on creating a safe and inclusive environment, encouraging honest feedback and productive discussions.
+
+ --------------------------------------------------
+ Topic Name: Remote Team Resources
+
+ Top Keywords: best collaboration tools for remote teams, slack best practices for remote teams, best communication tools for remote teams, best tools for remote teams, always on video for remote teams, best apps for remote teams, best free collaboration tools for remote teams, best games for remote teams, best gifts for remote teams, best ice breaker questions for remote teams
+
+ Blog Post Ideas: 1. Blog title: "The Ultimate Guide to Remote Team Collaboration Tools"
+ Abstract: With the rise of remote work, choosing the right collaboration tools can be crucial to a team's success and productivity. This blog aims to be an comprehensive guide, outlining the various types of tools available, from communication platforms like Slack to project management software and online collaboration tools. It will offer best practices and guidelines for selecting and utilizing these tools, ensuring remote teams can work seamlessly together and maximize their output.
+
+ 2. Blog title: "Remote Team Management: Tips for Leading a Successful Virtual Workforce"
+ Abstract: Managing a remote team comes with its own set of challenges. This blog will provide an in-depth exploration of best practices for leading and motivating virtual teams. Covering topics such as effective communication strategies, performance evaluation, and maintaining a cohesive team culture, it will offer practical tips for managers and leaders to ensure their remote teams are engaged, productive, and well-managed.
+
+ 3. Blog title: "The Fun Side of Remote Work: Games, Icebreakers, and Team Building Activities"
+ Abstract: Remote work can be isolating, and this blog aims to provide some fun and creative solutions. It will offer a comprehensive guide to the best online games, icebreaker questions, and virtual team building activities that remote teams can use to connect and bond. From virtual escape rooms to interactive games and thought-provoking icebreakers, these ideas will help enhance team spirit, foster collaboration, and create a enjoyable remote work experience.
+
+ --------------------------------------------------
+ Topic Name: Remote Team Fun
+
+ Top Keywords: online games for remote teams, team building activities for remote teams, games for remote teams, retrospective ideas for remote teams, team building ideas for remote teams, fun retrospective ideas for remote teams, retro ideas for remote teams, team building exercises for remote teams, trust building exercises for remote teams, activities for remote teams
+
+ Blog Post Ideas: 1. Blog title: "The Great Remote Retro: Fun Games and Activities for Your Team"
+ Abstract: Remote work can make team building challenging. This blog post will be a fun guide to hosting interactive retro games and activities that bring your remote team together. From online escape rooms to virtual scavenger hunts, we'll explore the best ways to engage and unite your team, fostering collaboration and camaraderie. Virtual icebreakers and retrospective ideas will also be included to make your remote meetings more interactive and enjoyable.
+
+ 2. Blog title: "Trust Falls: Building Trust Among Remote Teams"
+ Abstract: Trust is the foundation of every successful team, but how do you build it when everyone is scattered across different locations? This blog will focus on trust-building exercises and activities designed specifically for remote teams. From virtual trust falls to transparent communication practices, we'll discover innovative ways to strengthen team bonds and foster a culture of trust. You'll learn how to create an environment where your remote team can thrive and collaborate effectively.
+
+ 3. Blog title: "Game Night for Remote Teams: A Guide to Online Games and Activities"
+ Abstract: Miss the old office game nights? This blog will bring the fun back with a guide to hosting online game nights and activities that are perfect for remote teams. From trivia games to virtual board games and even remote-friendly outdoor adventures, we'll keep your team engaged and entertained. With tips on setting up online tournaments and ideas for encouraging participation, your virtual game nights will be the highlight of your team's week. Keep your remote team spirit high!
+
+ --------------------------------------------------
+
+
+
+```python
---------------------------------------------------
```
diff --git a/fern/pages/cookbooks/grounded-summarization.mdx b/fern/pages/cookbooks/grounded-summarization.mdx
index 098396302..bde9befb8 100644
--- a/fern/pages/cookbooks/grounded-summarization.mdx
+++ b/fern/pages/cookbooks/grounded-summarization.mdx
@@ -3,28 +3,41 @@ title: Grounded Summarization Using Command R
slug: /page/grounded-summarization
description: "This page contains a basic tutorial on how to do grounded summarization with Cohere's models."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, summarization, grounded generations, RAG, retrieval-augmented generation"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
Note: we are in the process of updating the links in this notebook. If a link doesn't work, please open an issue and we'll rectify it ASAP. Thanks for your understanding!
Links to add:
+* Cell 1: long-form, grounded summarisation blog post
+* Section 4: to text-rank method (context filtering)
-- Cell 1: long-form, grounded summarisation blog post
-- Section 4: to text-rank method (context filtering)
This notebook provides the code to produce the outputs described in [this blog post](https://docs.google.com/document/d/1Eeakpz_FZoeMzJnQieqQWCpPtQuNiTGW4fueU9J0QHA/edit).
-## 1. Setup [#setup]
+## Table of contents
+
+1. [Setup](#setup)
+2. [Out-of-the-box summarization with Command-R](#out-of-the-box-summarization-with-command-r)
+3. [Introduce citations to the summary for grounding](#introduce-citations-to-the-summary-for-grounding)
+4. [Reduce the cost of summarization calls](#reduce-the-cost-of-summarization-calls)
+
+
+
+## 1. Setup
-```python PYTHON
+
+```python
%%capture
+# TODO: upgrade to "cohere>5"!pip install "cohere<5" networkx
import cohere
import networkx as nx
@@ -39,13 +52,16 @@ from getpass import getpass
import re
from typing import List, Tuple
+# Set up Cohere client
co_api_key = getpass("Enter your Cohere API key: ")
co_model = "command-r"
co = cohere.Client(co_api_key)
```
-```python PYTHON
+
+```python
+# Read IMF report
from google.colab import drive
drive.mount("/content/drive", force_remount=True)
@@ -62,8 +78,11 @@ print(f"Loaded IMF report with {num_tokens} tokens")
### Aside: define utils
-```python PYTHON
+```python
+# Utils!
+
+# --- for chunking ---
def split_text_into_sentences(text: str) -> List[str]:
sentences = sent_tokenize(text)
return sentences
@@ -90,6 +109,7 @@ def build_simple_chunks(text, n_sentences: int = 10):
return chunks
+# --- for visualising citations ---
def insert_citations(text: str, citations: List[dict]):
"""
@@ -111,6 +131,7 @@ def insert_citations(text: str, citations: List[dict]):
return text
+# --- for reducing number of tokens sent to model intelligently ---
def textrank(text: str, co, max_tokens: int, n_sentences_per_passage: int) -> str:
"""
@@ -189,11 +210,14 @@ def _add_chunks_by_priority(
```
-## 2. Out-of-the-box summarization with Command-R [#out-of-the-box-summarization-with-command-r]
+
+
+## 2. Out-of-the-box summarization with Command-R
First, let's see Command-R's out-of-the-box performance. It's a 128k-context model, so we can pass the full IMF report in a single call. We replicate the exact instructions from the original tweet (correcting for a minor typo) for enabling fair comparisons.
-```python PYTHON
+
+```python
prompt_template = """\
## text
{text}
@@ -223,12 +247,14 @@ print(resp.text)
```
-# 3. Introduce citations to the summary for grounding [#introduce-citations-to-the-summary-for-grounding]
+
+
+## 3. Introduce citations to the summary for grounding
When summarizing long documents, introducing citations is one simple method for checking the factuality of the summary without needing to read the full document.
-We've trained Command-R to introduce citations whenever prompted by our grounded generations instructions. Triggering this grounded mode is straightforward. Starting from the previous snippet, we only need to make two changes:
+We've trained Command-R to introduce citations whenever prompted by our grounded generations instructions. Triggering this grounded mode is straightforward. Starting from the previous snippet, we only need to make two changes:
1. Pass our text to the `documents` argument
2. Pass our instructions to the `message` argument
@@ -236,7 +262,8 @@ For more information on how to enable grounded generation via our `co.chat` API,
Finally, note that we chunk the IMF report into multiple documents before passing them to `co.chat`. This isn't necessary (`co.chat` annotates citations at the character level), but allows for more human-readable citations.
-```python PYTHON
+
+```python
summarize_preamble = """\
You will receive a series of text fragments from an article that are presented in chronological order. \
As the assistant, you must generate responses to user's requests based on the information given in the fragments. \
@@ -250,7 +277,9 @@ Step 1. Read the entire text from the first to the last page.
Step 2. Create a summary of every chapter from the first to the last page.
"""
+# Chunk long text into multiple chunks for readable citations
chunked = build_simple_chunks(text, n_sentences=30)
+# Use `message` and `documents` arguments to trigger grounded generation
resp = co.chat(
preamble=summarize_preamble,
message=instructions,
@@ -259,6 +288,8 @@ resp = co.chat(
temperature=0.3,
return_prompt=True
)
+# Note: the grounded generation pipeline takes longer when documents are chunked
+# more finely. For latency-sensitive applications, try tuning the size of chunks!
num_tokens_in = co.tokenize(resp.prompt).length
num_tokens_out = resp.meta["billed_units"]["output_tokens"]
@@ -272,37 +303,43 @@ print(resp.text)
Let's display the citations inside our answer:
-```python PYTHON
+
+```python
print(insert_citations(resp.text, resp.citations))
```
We can now visualise which section of the answer is based on which passage in the main text. Verifying factuality is straightforward: pick a section and verify that the relevant information is contained in the cited chunk.
For instance, let's verify the statement
-
```
Around 40% of employment worldwide is exposed to AI [1, 6]
```
-
by checking its chunk:
-```python PYTHON
+
+```python
print(chunked[6])
```
Seems convincing!
By repeating such checks, it's straightforward to build trust in your summaries.
-# 4. Reduce the cost of summarization calls [#reduce-the-cost-of-summarization-calls]
+
+
+## 4. Reduce the cost of summarization calls
Even though Command-R is an efficient, light-weight model, for some applications we may accept trading off some summarization quality for lower costs. To do this, we must reduce the amount of tokens sent to the model -- but how do we select the most relevant bits?
We have a whole notebook dedicated to methods for reducing context length. Here, we call our 'text-rank' method to select maximally central chunks in a graph based on the chunk-to-chunk similarties. For more detail, please refer [to this cookbook](https://colab.research.google.com/drive/1zxSAbruOWwWJHNsj3N56uxZtUeiS7Evd).
-```python PYTHON
+
+```python
+# First, we filter the original text down to a smaller amount of tokens.
+# This will reduce cost and improve latency
num_tokens = 8192
shortened = textrank(text, co, num_tokens, n_sentences_per_passage=30)
+# Then, we apply grounded generation to keep citations on our (now shorter) report
chunked = build_simple_chunks(shortened)
resp = co.chat(
message=instructions,
diff --git a/fern/pages/cookbooks/hello-world-meet-ai.mdx b/fern/pages/cookbooks/hello-world-meet-ai.mdx
index 6ec731a3c..dc84493f3 100644
--- a/fern/pages/cookbooks/hello-world-meet-ai.mdx
+++ b/fern/pages/cookbooks/hello-world-meet-ai.mdx
@@ -1,54 +1,68 @@
---
-title: Hello World! Explore Language AI with Cohere
+title: Hello World! Meet Language AI
slug: /page/hello-world-meet-ai
description: "This page contains a breakdown of some of what can be achieved with Cohere's LLM platform."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, large language models, LLMs, generative AI"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
+
+
+
+
Here we take a quick tour of what’s possible with language AI via Cohere’s Large Language Model (LLM) API. This is the Hello, World! of language AI, written for developers with little or no background in AI. In fact, we’ll do that by exploring the Hello, World! phrase itself.
-Read the accompanying [blog post here](https://cohere.com/blog/hello-world-p1/).
+Read the accompanying [blog post here](https://txt.cohere.ai/hello-world-p1/).
-
+
We’ll cover three groups of tasks that you will typically work on when dealing with language data, including:
-
- Generating text
- Classifying text
- Analyzing text
-The first step is to install the Cohere Python SDK. Next, create an API key, which you can generate from the Cohere [dashboard](https://dashboard.cohere.com/register) or [CLI tool](https://docs.cohere.ai/cli-key).
-```python PYTHON
+The first step is to install the Cohere Python SDK. Next, create an API key, which you can generate from the Cohere [dashboard](https://os.cohere.ai/register) or [CLI tool](https://docs.cohere.ai/cli-key).
+
+
+```python
+# Install the libraries
! pip install cohere altair umap-learn -q
```
-```python PYTHON
+
+```python
+# Import the libraries
import cohere
import pandas as pd
import numpy as np
import altair as alt
+# Setup the Cohere client
co = cohere.Client("COHERE_API_KEY") # Get your API key: https://dashboard.cohere.com/api-keys
```
-The Cohere Generate endpoint generates text given an input, called “prompt”. The prompt provides a context of what we want the model to generate text. To illustrate this, let’s start with a simple prompt as the input.
+# 1 - Generating Text
+
+The Cohere Generate endpoint generates text given an input, called “prompt”. The prompt provides a context of what we want the model to generate text. To illustrate this, let’s start with a simple prompt as the input.
### Try a Simple Prompt
-```python PYTHON
+
+```python
+# Create a simple one-line prompt
prompt = "What is a Hello World program."
+# Generate text by calling the Chat endpoint
response = co.chat(
message=prompt,
model='command-r')
@@ -56,56 +70,62 @@ response = co.chat(
print(response.text)
```
-````
-A "Hello World" program is a traditional and simple program that is often used as an introduction to a new programming language. The program typically displays the message "Hello World" as its output. The concept of a "Hello World" program originated from the book *The C Programming Language* written by Kernighan and Ritchie, where the example program in the book displayed the message using the C programming language.
-
-The "Hello World" program serves as a basic and straightforward way to verify that your development environment is set up correctly and to familiarize yourself with the syntax and fundamentals of the programming language. It's a starting point for learning how to write and run programs in a new language.
-
-The program's simplicity makes it accessible to programmers of all skill levels, and it's often one of the first programs beginners write when learning to code. The exact implementation of a "Hello World" program varies depending on the programming language being used, but the core idea remains the same—to display the "Hello World" message.
-
-Here's how a "Hello World" program can be written in a few select languages:
-1. **C**:
-```c
-#include
-int main() {
- printf("Hello World\n");
- return 0;
-}
-```
-2. **Python**:
-```python PYTHON
-print("Hello World")
-```
-3. **Java**:
-```java JAVA
-class HelloWorld {
- public static void main(String[] args) {
- System.out.println("Hello World");
+ A "Hello World" program is a traditional and simple program that is often used as an introduction to a new programming language. The program typically displays the message "Hello World" as its output. The concept of a "Hello World" program originated from the book *The C Programming Language* written by Kernighan and Ritchie, where the example program in the book displayed the message using the C programming language.
+
+ The "Hello World" program serves as a basic and straightforward way to verify that your development environment is set up correctly and to familiarize yourself with the syntax and fundamentals of the programming language. It's a starting point for learning how to write and run programs in a new language.
+
+ The program's simplicity makes it accessible to programmers of all skill levels, and it's often one of the first programs beginners write when learning to code. The exact implementation of a "Hello World" program varies depending on the programming language being used, but the core idea remains the same—to display the "Hello World" message.
+
+ Here's how a "Hello World" program can be written in a few select languages:
+ 1. **C**:
+ ```c
+ #include
+ int main() {
+ printf("Hello World\n");
+ return 0;
}
-}
-```
-4. **JavaScript**:
-```javascript
-console.log("Hello World");
-```
-5. **C#**:
-```csharp
-using System;
-
-class Program {
- static void Main() {
- Console.WriteLine("Hello World");
+ ```
+
+ 2. **Python**:
+ ```python
+ print("Hello World")
+ ```
+
+ 3. **Java**:
+ ```java
+ class HelloWorld {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
}
-}
-```
-The "Hello World" program is a testament to the power of programming, as a simple and concise message can be displayed in numerous languages with just a few lines of code. It's an exciting first step into the world of software development!
-````
+ ```
+
+ 4. **JavaScript**:
+ ```javascript
+ console.log("Hello World");
+ ```
+
+ 5. **C#**:
+ ```csharp
+ using System;
+
+ class Program {
+ static void Main() {
+ Console.WriteLine("Hello World");
+ }
+ }
+ ```
+
+ The "Hello World" program is a testament to the power of programming, as a simple and concise message can be displayed in numerous languages with just a few lines of code. It's an exciting first step into the world of software development!
+
### Create a Better Prompt
-The output is not bad, but it can be better. We need to find a way to make the output tighter to how we want it to be, which is where we leverage _prompt engineering_.
+The output is not bad, but it can be better. We need to find a way to make the output tighter to how we want it to be, which is where we leverage *prompt engineering*.
+
-```python PYTHON
+```python
+# Create a prompt containing a short description, examples, and stop sequences
prompt = """
Write the first paragraph of a blog post given a blog title.
--
@@ -123,6 +143,7 @@ solve dynamic programming problems.
Blog Title: Learning to Code with Hello, World!
First Paragraph:"""
+# Generate text by calling the Chat endpoint
response = co.chat(
message=prompt,
model='command-r')
@@ -130,15 +151,16 @@ response = co.chat(
print(response.text)
```
-```
-Starting to code can be daunting, but it's actually simpler than you think! The famous first program, "Hello, World!" is a rite of passage for all coders, and an excellent starting point to begin your coding journey. This blog will guide you through the process of writing your very first line of code, and help you understand why learning to code is an exciting and valuable skill to have, covering the fundamentals and the broader implications of this seemingly simple phrase.
-```
+ Starting to code can be daunting, but it's actually simpler than you think! The famous first program, "Hello, World!" is a rite of passage for all coders, and an excellent starting point to begin your coding journey. This blog will guide you through the process of writing your very first line of code, and help you understand why learning to code is an exciting and valuable skill to have, covering the fundamentals and the broader implications of this seemingly simple phrase.
+
### Automating the Process
In real applications, you will likely need to produce these text generations on an ongoing basis, given different inputs. Let’s simulate that with our example.
-```python PYTHON
+
+```python
+# A function that generates text given a base prompt and a new topic
def generate_text(topic):
prompt = f"""
Write the first paragraph of a blog post given a blog title.
@@ -164,63 +186,73 @@ First Paragraph:"""
return response.text
```
-```python PYTHON
+
+```python
+# The list of topics
topics = ["How to Grow in Your Career",
"The Habits of Great Software Developers",
"Ideas for a Relaxing Weekend"]
```
-```python PYTHON
+
+```python
+# Keep the generations in a list of paragraphs
paragraphs = []
for topic in topics:
paragraphs.append(generate_text(topic))
-
+
+# Display the generated paragraphs
for topic,para in zip(topics,paragraphs):
print(f"Topic: {topic}")
print(f"First Paragraph: {para}")
print("-"*10)
```
-```
-Topic: How to Grow in Your Career
-First Paragraph: Advancing in your career can seem like a daunting task, especially if you're unsure of the path ahead. In this ever-changing professional landscape, there are numerous factors to consider. This blog aims to shed light on the strategies and skills that can help you navigate the complexities of career progression and unlock your full potential. Whether you're looking to secure a promotion or explore new opportunities, these insights will help you chart a course for your future. Let's embark on this journey of self-improvement and professional growth, equipping you with the tools to succeed in your career aspirations.
-----------
-Topic: The Habits of Great Software Developers
-First Paragraph: Great software developers are renowned for their ability to write robust code and create innovative applications, but what sets them apart from their peers? In this blog, we'll delve into the daily habits that contribute to their success. From their approach to coding challenges to the ways they stay organized, we'll explore the routines and practices that help them excel in the fast-paced world of software development. Understanding these habits can help you elevate your own skills and join the ranks of these industry leaders.
-----------
-Topic: Ideas for a Relaxing Weekend
-First Paragraph: Life can be stressful, and sometimes we just need a relaxing weekend to unwind and recharge. In this fast-paced world, taking some time to slow down and rejuvenate is essential. This blog post is here to help you plan the perfect low-key weekend with some easy and accessible ideas. From cozy indoor activities to peaceful outdoor adventures, I'll share some ideas to help you renew your mind, body, and spirit. Whether you're a homebody or an adventure seeker, there's something special for everyone. So, grab a cup of tea, sit back, and get ready to dive into a calming weekend of self-care and relaxation!
-----------
-```
+ Topic: How to Grow in Your Career
+ First Paragraph: Advancing in your career can seem like a daunting task, especially if you're unsure of the path ahead. In this ever-changing professional landscape, there are numerous factors to consider. This blog aims to shed light on the strategies and skills that can help you navigate the complexities of career progression and unlock your full potential. Whether you're looking to secure a promotion or explore new opportunities, these insights will help you chart a course for your future. Let's embark on this journey of self-improvement and professional growth, equipping you with the tools to succeed in your career aspirations.
+ ----------
+ Topic: The Habits of Great Software Developers
+ First Paragraph: Great software developers are renowned for their ability to write robust code and create innovative applications, but what sets them apart from their peers? In this blog, we'll delve into the daily habits that contribute to their success. From their approach to coding challenges to the ways they stay organized, we'll explore the routines and practices that help them excel in the fast-paced world of software development. Understanding these habits can help you elevate your own skills and join the ranks of these industry leaders.
+ ----------
+ Topic: Ideas for a Relaxing Weekend
+ First Paragraph: Life can be stressful, and sometimes we just need a relaxing weekend to unwind and recharge. In this fast-paced world, taking some time to slow down and rejuvenate is essential. This blog post is here to help you plan the perfect low-key weekend with some easy and accessible ideas. From cozy indoor activities to peaceful outdoor adventures, I'll share some ideas to help you renew your mind, body, and spirit. Whether you're a homebody or an adventure seeker, there's something special for everyone. So, grab a cup of tea, sit back, and get ready to dive into a calming weekend of self-care and relaxation!
+ ----------
+
+
+# 2 - Classifying Text
Cohere’s Classify endpoint makes it easy to take a list of texts and predict their categories, or classes. A typical machine learning model requires many training examples to perform text classification, but with the Classify endpoint, you can get started with as few as 5 examples per class.
### Sentiment Analysis
-```python PYTHON
+
+```python
+# Create the training examples for the classifier
from cohere import ClassifyExample
examples = [
- ClassifyExample(text="I’m so proud of you", label="positive"),
- ClassifyExample(text="What a great time to be alive", label="positive"),
- ClassifyExample(text="That’s awesome work", label="positive"),
- ClassifyExample(text="The service was amazing", label="positive"),
- ClassifyExample(text="I love my family", label="positive"),
- ClassifyExample(text="They don't care about me", label="negative"),
- ClassifyExample(text="I hate this place", label="negative"),
- ClassifyExample(text="The most ridiculous thing I've ever heard", label="negative"),
- ClassifyExample(text="I am really frustrated", label="negative"),
+ ClassifyExample(text="I’m so proud of you", label="positive"),
+ ClassifyExample(text="What a great time to be alive", label="positive"),
+ ClassifyExample(text="That’s awesome work", label="positive"),
+ ClassifyExample(text="The service was amazing", label="positive"),
+ ClassifyExample(text="I love my family", label="positive"),
+ ClassifyExample(text="They don't care about me", label="negative"),
+ ClassifyExample(text="I hate this place", label="negative"),
+ ClassifyExample(text="The most ridiculous thing I've ever heard", label="negative"),
+ ClassifyExample(text="I am really frustrated", label="negative"),
ClassifyExample(text="This is so unfair", label="negative"),
- ClassifyExample(text="This made me think", label="neutral"),
- ClassifyExample(text="The good old days", label="neutral"),
- ClassifyExample(text="What's the difference", label="neutral"),
- ClassifyExample(text="You can't ignore this", label="neutral"),
+ ClassifyExample(text="This made me think", label="neutral"),
+ ClassifyExample(text="The good old days", label="neutral"),
+ ClassifyExample(text="What's the difference", label="neutral"),
+ ClassifyExample(text="You can't ignore this", label="neutral"),
ClassifyExample(text="That's how I see it", label="neutral")
]
```
-```python PYTHON
+
+```python
+# Enter the inputs to be classified
inputs=["Hello, world! What a beautiful day",
"It was a great time with great people",
"Great place to work",
@@ -236,7 +268,9 @@ inputs=["Hello, world! What a beautiful day",
]
```
-```python PYTHON
+
+```python
+# A function that classifies a list of inputs given the examples
def classify_text(inputs, examples):
"""
Classify a list of input texts
@@ -251,15 +285,18 @@ def classify_text(inputs, examples):
model='embed-english-v2.0',
inputs=inputs,
examples=examples)
-
+
classifications = response.classifications
-
+
return classifications
```
-```python PYTHON
+
+```python
+# Classify the inputs
predictions = classify_text(inputs,examples)
+# Display the classification outcomes
classes = ["positive","negative","neutral"]
for inp,pred in zip(inputs,predictions):
class_pred = pred.predictions[0]
@@ -272,104 +309,128 @@ for inp,pred in zip(inputs,predictions):
print("-"*10)
```
-```
-Input: Hello, world! What a beautiful day
-Prediction: positive
-Confidence: 0.84
-----------
-Input: It was a great time with great people
-Prediction: positive
-Confidence: 0.99
-----------
-Input: Great place to work
-Prediction: positive
-Confidence: 0.91
-----------
-Input: That was a wonderful evening
-Prediction: positive
-Confidence: 0.96
-----------
-Input: Maybe this is why
-Prediction: neutral
-Confidence: 0.70
-----------
-Input: Let's start again
-Prediction: neutral
-Confidence: 0.83
-----------
-Input: That's how I see it
-Prediction: neutral
-Confidence: 1.00
-----------
-Input: These are all facts
-Prediction: neutral
-Confidence: 0.78
-----------
-Input: This is the worst thing
-Prediction: negative
-Confidence: 0.93
-----------
-Input: I cannot stand this any longer
-Prediction: negative
-Confidence: 0.93
-----------
-Input: This is really annoying
-Prediction: negative
-Confidence: 0.99
-----------
-Input: I am just plain fed up
-Prediction: negative
-Confidence: 1.00
-----------
-```
+ Input: Hello, world! What a beautiful day
+ Prediction: positive
+ Confidence: 0.84
+ ----------
+ Input: It was a great time with great people
+ Prediction: positive
+ Confidence: 0.99
+ ----------
+ Input: Great place to work
+ Prediction: positive
+ Confidence: 0.91
+ ----------
+ Input: That was a wonderful evening
+ Prediction: positive
+ Confidence: 0.96
+ ----------
+ Input: Maybe this is why
+ Prediction: neutral
+ Confidence: 0.70
+ ----------
+ Input: Let's start again
+ Prediction: neutral
+ Confidence: 0.83
+ ----------
+ Input: That's how I see it
+ Prediction: neutral
+ Confidence: 1.00
+ ----------
+ Input: These are all facts
+ Prediction: neutral
+ Confidence: 0.78
+ ----------
+ Input: This is the worst thing
+ Prediction: negative
+ Confidence: 0.93
+ ----------
+ Input: I cannot stand this any longer
+ Prediction: negative
+ Confidence: 0.93
+ ----------
+ Input: This is really annoying
+ Prediction: negative
+ Confidence: 0.99
+ ----------
+ Input: I am just plain fed up
+ Prediction: negative
+ Confidence: 1.00
+ ----------
+
+
+# 3 - Analyzing Text
Cohere’s Embed endpoint takes a piece of text and turns it into a vector embedding. Embeddings represent text in the form of numbers that capture its meaning and context. What it means is that it gives you the ability to turn unstructured text data into a structured form. It opens up ways to analyze and extract insights from them.
+
## Get embeddings
Here we have a list of 50 top web search keywords about Hello, World! taken from a keyword tool. Let’s look at a few examples:
-```python PYTHON
+
+```python
+# Get a list of texts and add to a dataframe
df = pd.read_csv("https://github.com/cohere-ai/cohere-developer-experience/raw/main/notebooks/data/hello-world-kw.csv", names=["search_term"])
df.head()
```
+
+
+
-
-
-
- |
- search_term |
-
-
-
-
- 0 |
- how to print hello world in python |
-
-
- 1 |
- what is hello world |
-
-
- 2 |
- how do you write hello world in an alert box |
-
-
- 3 |
- how to print hello world in java |
-
-
- 4 |
- how to write hello world in eclipse |
-
-
-
+
+
+
+
+ |
+ search_term |
+
+
+
+
+ 0 |
+ how to print hello world in python |
+
+
+ 1 |
+ what is hello world |
+
+
+ 2 |
+ how do you write hello world in an alert box |
+
+
+ 3 |
+ how to print hello world in java |
+
+
+ 4 |
+ how to write hello world in eclipse |
+
+
+
+
+
We use the Embed endpoint to get the embeddings for each of these keywords.
-```python PYTHON
+
+```python
+# A function that classifies a list of inputs given the examples
def embed_text(texts, input_type):
"""
Turns a piece of text into embeddings
@@ -383,11 +444,13 @@ def embed_text(texts, input_type):
model="embed-english-v3.0",
input_type=input_type,
texts=texts)
-
+
return response.embeddings
```
-```python PYTHON
+
+```python
+# Get embeddings of all search terms
df["search_term_embeds"] = embed_text(texts=df["search_term"].tolist(),
input_type="search_document")
doc_embeds = np.array(df["search_term_embeds"].tolist())
@@ -397,16 +460,22 @@ doc_embeds = np.array(df["search_term_embeds"].tolist())
We’ll look at a couple of example applications. The first example is semantic search. Given a new query, our "search engine" must return the most similar FAQs, where the FAQs are the 50 search terms we uploaded earlier.
-```python PYTHON
+
+
+```python
+# Add a new query
query = "what is the history of hello world"
+# Get embeddings of the new query
query_embeds = embed_text(texts=[query],
input_type="search_query")[0]
```
We use cosine similarity to compare the similarity of the new query with each of the FAQs
-```python PYTHON
+
+```python
+# Calculate cosine similarity
from sklearn.metrics.pairwise import cosine_similarity
@@ -437,9 +506,12 @@ def get_similarity(target, candidates):
Finally, we display the top 5 FAQs that match the new query
-```python PYTHON
+
+```python
+# Get the similarity between the new query and existing queries
similarity = get_similarity(query_embeds,doc_embeds)
+# Display the top 5 FAQs
print("New query:")
print(new_query,'\n')
@@ -448,17 +520,16 @@ for idx,score in similarity[:5]:
print(f"Similarity: {score:.2f};", df.iloc[idx]["search_term"])
```
-```
-New query:
-what is the history of hello world
-
-Similar queries:
-Similarity: 0.58; how did hello world originate
-Similarity: 0.56; where did hello world come from
-Similarity: 0.54; why hello world
-Similarity: 0.53; why is hello world so famous
-Similarity: 0.53; what is hello world
-```
+ New query:
+ what is the history of hello world
+
+ Similar queries:
+ Similarity: 0.58; how did hello world originate
+ Similarity: 0.56; where did hello world come from
+ Similarity: 0.54; why hello world
+ Similarity: 0.53; why is hello world so famous
+ Similarity: 0.53; what is hello world
+
### Semantic Exploration
@@ -466,16 +537,21 @@ In the second example, we take the same idea as semantic search and take a broad
We'll use the same 50 top web search terms about Hello, World! There are different techniques we can use to compress the embeddings down to just 2 dimensions while retaining as much information as possible. We'll use a technique called UMAP. And once we can get it down to 2 dimensions, we can plot these embeddings on a 2D chart.
-```python PYTHON
+
+```python
+# Reduce the embeddings' dimensions to 2 using UMAP
import umap
-reducer = umap.UMAP(n_neighbors=49)
+reducer = umap.UMAP(n_neighbors=49)
umap_embeds = reducer.fit_transform(doc_embeds)
+# Add the 2 dimensions to the dataframe
df['x'] = umap_embeds[:,0]
df['y'] = umap_embeds[:,1]
```
-```python PYTHON
+
+```python
+# Plot the 2-dimension embeddings on a chart
chart = alt.Chart(df).mark_circle(size=500).encode(
x=
alt.X('x',
@@ -488,7 +564,7 @@ chart = alt.Chart(df).mark_circle(size=500).encode(
scale=alt.Scale(zero=False),
axis=alt.Axis(labels=False, ticks=False, domain=False)
),
-
+
tooltip=['search_term']
)
@@ -505,4 +581,27 @@ result = (chart + text).configure(background="#FDF7F0"
result
```
+
+
+
+
+
+
+
+
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/long-form-general-strategies.mdx b/fern/pages/cookbooks/long-form-general-strategies.mdx
index e5dd17a9f..ca43311d6 100644
--- a/fern/pages/cookbooks/long-form-general-strategies.mdx
+++ b/fern/pages/cookbooks/long-form-general-strategies.mdx
@@ -1,9 +1,9 @@
---
-title: Long-Form Text Strategies with Cohere
+title: Long Form General Strategies
slug: /page/long-form-general-strategies
description: "This discusses ways of getting Cohere's LLM platform to perform well in generating long-form text."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, text comprehension, reading comprehension, AI, context windows"
---
@@ -14,12 +14,15 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Ania Bialas",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/c5dc5a3-Ania.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/c5dc5a3-Ania.jpg"
+ }
]}
/>
-
+
+
+
+
Large Language Models (LLMs) are becoming increasingly capable of comprehending text, among others excelling in document analysis. The new Cohere model, [Command-R](https://huggingface.co/CohereForAI/c4ai-command-r-v01), boasts a context length of 128k, which makes it particularly effective for such tasks. Nevertheless, even with the extended context window, some documents might be too lengthy to accommodate in full.
@@ -27,28 +30,230 @@ In this cookbook, we'll explore techniques to address cases when relevant inform
We'll show you three potential mitigation strategies: truncating the document, query-based retrieval, and a "text rank" approach we use internally at Cohere.
-## Summary
+### Table of content:
+1. [Getting started](#getting-started)
+2. [Approach 1: Truncate](#truncate)
+3. [Approach 2: Query Based Retrieval](#query-based-retrieval)
+4. [Approach 3: Text Rank](#text-rank)
+
+### Summary
+
+| Approach | Description | Pros | Cons | When to use? |
+|-----------------------|-------------------------------------------|-------------------------------------------|-------------------------------------------|-------------------------------------------|
+| Truncation | Truncate the document to fit the context window. | - Simplicity of implementation
(does not rely on extrenal infrastructure)| - Loses information at the end of the document | Utilize when all relevant information is contained
at the beginning of the document. |
+| Query Based Retrieval| Utilize semantic similarity to retrieve text chunks
that are most relevant to the query. | - Focuses on sections directly relevant to
the query | - Relies on a semantic similarity algorithm.
- Might lose broader context | Employ when seeking specific
information within the text. |
+| Text Rank | Apply graph theory to generate a cohesive set
of chunks that effectively represent the document. | - Preserves the broader picture. | - Might lose detailed information. | Utilize in summaries and when the question
requires broader context. |
+
+
+
+
+
+
-| Approach | Description | Pros | Cons | When to use? |
-| --------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
-| Truncation | Truncate the document to fit the context window. | - Simplicity of implementation
(does not rely on extrenal infrastructure) | - Loses information at the end of the document | Utilize when all relevant information is contained
at the beginning of the document. |
-| Query Based Retrieval | Utilize semantic similarity to retrieve text chunks
that are most relevant to the query. | - Focuses on sections directly relevant to
the query | - Relies on a semantic similarity algorithm.
- Might lose broader context | Employ when seeking specific
information within the text. |
-| Text Rank | Apply graph theory to generate a cohesive set
of chunks that effectively represent the document. | - Preserves the broader picture. | - Might lose detailed information. | Utilize in summaries and when the question
requires broader context. |
-
-## Getting Started [#getting-started]
-
-```python PYTHON
-%%capture
-!pip install cohere
-!pip install python-dotenv
-!pip install tokenizers
-!pip install langchain
-!pip install nltk
-!pip install networkx
-!pip install pypdf2
+
+
+
+
+```python
+####################################################################################################
+#
+# Uncomment if you need to install the following packages
+#
+####################################################################################################
+# %%capture
+# !pip install cohere
+# !pip install python-dotenv
+# !pip install tokenizers
+# !pip install langchain
+# !pip install nltk
+# !pip install networkx
+# !pip install pypdf2
```
-```python PYTHON
+ Collecting cohere
+ Downloading cohere-4.54-py3-none-any.whl (52 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m52.8/52.8 kB[0m [31m1.7 MB/s[0m eta [36m0:00:00[0m
+ [?25hRequirement already satisfied: aiohttp<4.0,>=3.0 in /usr/local/lib/python3.10/dist-packages (from cohere) (3.9.3)
+ Collecting backoff<3.0,>=2.0 (from cohere)
+ Downloading backoff-2.2.1-py3-none-any.whl (15 kB)
+ Collecting fastavro<2.0,>=1.8 (from cohere)
+ Downloading fastavro-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m3.1/3.1 MB[0m [31m33.1 MB/s[0m eta [36m0:00:00[0m
+ [?25hCollecting importlib_metadata<7.0,>=6.0 (from cohere)
+ Downloading importlib_metadata-6.11.0-py3-none-any.whl (23 kB)
+ Requirement already satisfied: requests<3.0.0,>=2.25.0 in /usr/local/lib/python3.10/dist-packages (from cohere) (2.31.0)
+ Requirement already satisfied: urllib3<3,>=1.26 in /usr/local/lib/python3.10/dist-packages (from cohere) (2.0.7)
+ Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (1.3.1)
+ Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (23.2.0)
+ Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (1.4.1)
+ Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (6.0.5)
+ Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (1.9.4)
+ Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0,>=3.0->cohere) (4.0.3)
+ Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.10/dist-packages (from importlib_metadata<7.0,>=6.0->cohere) (3.17.0)
+ Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0,>=2.25.0->cohere) (3.3.2)
+ Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0,>=2.25.0->cohere) (3.6)
+ Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0,>=2.25.0->cohere) (2024.2.2)
+ [31mERROR: Operation cancelled by user[0m[31m
+ [0mTraceback (most recent call last):
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/base_command.py", line 169, in exc_logging_wrapper
+ status = run_func(*args)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/req_command.py", line 242, in wrapper
+ return func(self, options, args)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/commands/install.py", line 324, in run
+ session = self.get_default_session(options)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/req_command.py", line 98, in get_default_session
+ self._session = self.enter_context(self._build_session(options))
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/req_command.py", line 125, in _build_session
+ session = PipSession(
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/network/session.py", line 342, in __init__
+ self.headers["User-Agent"] = user_agent()
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/network/session.py", line 175, in user_agent
+ setuptools_dist = get_default_environment().get_distribution("setuptools")
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/metadata/__init__.py", line 75, in get_default_environment
+ return select_backend().Environment.default()
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/metadata/__init__.py", line 63, in select_backend
+ from . import pkg_resources
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/metadata/pkg_resources.py", line 8, in
+ from pip._vendor import pkg_resources
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 3327, in
+ def _initialize_master_working_set():
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 3301, in _call_aside
+ f(*args, **kwargs)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 3339, in _initialize_master_working_set
+ working_set = WorkingSet._build_master()
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 620, in _build_master
+ ws = cls()
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 613, in __init__
+ self.add_entry(entry)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 669, in add_entry
+ for dist in find_distributions(entry, True):
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 2130, in find_on_path
+ for entry in sorted(entries):
+ File "/usr/local/lib/python3.10/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 2127, in
+ entries = (os.path.join(path_item, child) for child in safe_listdir(path_item))
+ File "/usr/lib/python3.10/posixpath.py", line 71, in join
+ def join(a, *p):
+ KeyboardInterrupt
+
+ During handling of the above exception, another exception occurred:
+
+ Traceback (most recent call last):
+ File "/usr/local/bin/pip3", line 8, in
+ sys.exit(main())
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/main.py", line 79, in main
+ return command.main(cmd_args)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/base_command.py", line 101, in main
+ return self._main(args)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/base_command.py", line 223, in _main
+ return run(options, args)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/cli/base_command.py", line 206, in exc_logging_wrapper
+ logger.critical("Operation cancelled by user")
+ File "/usr/lib/python3.10/logging/__init__.py", line 1524, in critical
+ self._log(CRITICAL, msg, args, **kwargs)
+ File "/usr/lib/python3.10/logging/__init__.py", line 1624, in _log
+ self.handle(record)
+ File "/usr/lib/python3.10/logging/__init__.py", line 1634, in handle
+ self.callHandlers(record)
+ File "/usr/lib/python3.10/logging/__init__.py", line 1696, in callHandlers
+ hdlr.handle(record)
+ File "/usr/lib/python3.10/logging/__init__.py", line 968, in handle
+ self.emit(record)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/utils/logging.py", line 168, in emit
+ message = self.format(record)
+ File "/usr/lib/python3.10/logging/__init__.py", line 943, in format
+ return fmt.format(record)
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/utils/logging.py", line 119, in format
+ prefix += " " * get_indentation()
+ File "/usr/local/lib/python3.10/dist-packages/pip/_internal/utils/logging.py", line 69, in get_indentation
+ def get_indentation() -> int:
+ KeyboardInterrupt
+ ^C
+ Requirement already satisfied: tokenizers in /usr/local/lib/python3.10/dist-packages (0.15.2)
+ Requirement already satisfied: huggingface_hub<1.0,>=0.16.4 in /usr/local/lib/python3.10/dist-packages (from tokenizers) (0.20.3)
+ Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (3.13.1)
+ Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (2023.6.0)
+ Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (2.31.0)
+ Requirement already satisfied: tqdm>=4.42.1 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (4.66.2)
+ Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (6.0.1)
+ Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (4.10.0)
+ Requirement already satisfied: packaging>=20.9 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers) (23.2)
+ Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers) (3.3.2)
+ Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers) (3.6)
+ Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers) (2.0.7)
+ Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers) (2024.2.2)
+ [31mERROR: Operation cancelled by user[0m[31m
+ [0mCollecting langchain
+ Downloading langchain-0.1.11-py3-none-any.whl (807 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m807.5/807.5 kB[0m [31m5.4 MB/s[0m eta [36m0:00:00[0m
+ [?25hRequirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (6.0.1)
+ Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.0.28)
+ Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (3.9.3)
+ Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (4.0.3)
+ Collecting dataclasses-json<0.7,>=0.5.7 (from langchain)
+ Downloading dataclasses_json-0.6.4-py3-none-any.whl (28 kB)
+ Collecting jsonpatch<2.0,>=1.33 (from langchain)
+ Downloading jsonpatch-1.33-py2.py3-none-any.whl (12 kB)
+ Collecting langchain-community<0.1,>=0.0.25 (from langchain)
+ Downloading langchain_community-0.0.27-py3-none-any.whl (1.8 MB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.8/1.8 MB[0m [31m7.7 MB/s[0m eta [36m0:00:00[0m
+ [?25hCollecting langchain-core<0.2,>=0.1.29 (from langchain)
+ Downloading langchain_core-0.1.30-py3-none-any.whl (256 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m256.9/256.9 kB[0m [31m18.7 MB/s[0m eta [36m0:00:00[0m
+ [?25hCollecting langchain-text-splitters<0.1,>=0.0.1 (from langchain)
+ Downloading langchain_text_splitters-0.0.1-py3-none-any.whl (21 kB)
+ Collecting langsmith<0.2.0,>=0.1.17 (from langchain)
+ Downloading langsmith-0.1.23-py3-none-any.whl (66 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m66.6/66.6 kB[0m [31m7.2 MB/s[0m eta [36m0:00:00[0m
+ [?25hRequirement already satisfied: numpy<2,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.25.2)
+ Requirement already satisfied: pydantic<3,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.6.3)
+ Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.31.0)
+ Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (8.2.3)
+ Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.1)
+ Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (23.2.0)
+ Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.4.1)
+ Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.5)
+ Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.9.4)
+ Collecting marshmallow<4.0.0,>=3.18.0 (from dataclasses-json<0.7,>=0.5.7->langchain)
+ Downloading marshmallow-3.21.1-py3-none-any.whl (49 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m49.4/49.4 kB[0m [31m5.2 MB/s[0m eta [36m0:00:00[0m
+ [?25hCollecting typing-inspect<1,>=0.4.0 (from dataclasses-json<0.7,>=0.5.7->langchain)
+ Downloading typing_inspect-0.9.0-py3-none-any.whl (8.8 kB)
+ Collecting jsonpointer>=1.9 (from jsonpatch<2.0,>=1.33->langchain)
+ Downloading jsonpointer-2.4-py2.py3-none-any.whl (7.8 kB)
+ Requirement already satisfied: anyio<5,>=3 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2,>=0.1.29->langchain) (3.7.1)
+ Requirement already satisfied: packaging<24.0,>=23.2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2,>=0.1.29->langchain) (23.2)
+ Collecting orjson<4.0.0,>=3.9.14 (from langsmith<0.2.0,>=0.1.17->langchain)
+ Downloading orjson-3.9.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (138 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m138.5/138.5 kB[0m [31m15.4 MB/s[0m eta [36m0:00:00[0m
+ [?25hRequirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (0.6.0)
+ Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (2.16.3)
+ Requirement already satisfied: typing-extensions>=4.6.1 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (4.10.0)
+ Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.3.2)
+ Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.6)
+ Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2.0.7)
+ Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2024.2.2)
+ Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain) (3.0.3)
+ Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2,>=0.1.29->langchain) (1.3.1)
+ Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2,>=0.1.29->langchain) (1.2.0)
+ Collecting mypy-extensions>=0.3.0 (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain)
+ Downloading mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB)
+ Installing collected packages: orjson, mypy-extensions, marshmallow, jsonpointer, typing-inspect, jsonpatch, langsmith, dataclasses-json, langchain-core, langchain-text-splitters, langchain-community, langchain
+ Successfully installed dataclasses-json-0.6.4 jsonpatch-1.33 jsonpointer-2.4 langchain-0.1.11 langchain-community-0.0.27 langchain-core-0.1.30 langchain-text-splitters-0.0.1 langsmith-0.1.23 marshmallow-3.21.1 mypy-extensions-1.0.0 orjson-3.9.15 typing-inspect-0.9.0
+ Requirement already satisfied: nltk in /usr/local/lib/python3.10/dist-packages (3.8.1)
+ Requirement already satisfied: click in /usr/local/lib/python3.10/dist-packages (from nltk) (8.1.7)
+ Requirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from nltk) (1.3.2)
+ Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.10/dist-packages (from nltk) (2023.12.25)
+ Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from nltk) (4.66.2)
+ Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (3.2.1)
+ Collecting pypdf2
+ Downloading pypdf2-3.0.1-py3-none-any.whl (232 kB)
+ [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m232.6/232.6 kB[0m [31m4.1 MB/s[0m eta [36m0:00:00[0m
+ [?25hInstalling collected packages: pypdf2
+ Successfully installed pypdf2-3.0.1
+
+
+
+```python
import os
import requests
from collections import deque
@@ -72,20 +277,85 @@ from getpass import getpass
from IPython.display import HTML, display
```
-```txt title="Output"
-[nltk_data] Downloading package punkt to
-[nltk_data] /home/anna_cohere_com/nltk_data...
-[nltk_data] Package punkt is already up-to-date!
+ [nltk_data] Downloading package punkt to /root/nltk_data...
+ [nltk_data] Package punkt is already up-to-date!
+
+
+
+
+
+ False
+
+
+
+
+```python
+def set_css():
+ display(HTML('''
+
+ '''))
+get_ipython().events.register('pre_run_cell', set_css)
+
+set_css()
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
# Set up Cohere client
co_model = 'command-r'
co_api_key = getpass("Enter your Cohere API key: ")
co = cohere.Client(api_key=co_api_key)
```
-```python PYTHON
+ Enter your Cohere API key: ··········
+
+
+
+```python
def load_long_pdf(file_path):
"""
Load a long PDF file and extract its text content.
@@ -124,7 +394,8 @@ def save_pdf_from_url(pdf_url, save_path):
In this example we use the Proposal for a Regulation of the European Parliament and of the Council defining rules on Artificial Intelligence from 26 January 2024, [link](https://data.consilium.europa.eu/doc/document/ST-5662-2024-INIT/en/pdf).
-```python PYTHON
+
+```python
# Download the PDF file from the URL
pdf_url = 'https://data.consilium.europa.eu/doc/document/ST-5662-2024-INIT/en/pdf'
save_path = 'example.pdf'
@@ -135,17 +406,57 @@ long_text = load_long_pdf(save_path)
long_text = long_text.replace('\n', ' ')
# Print the length of the document
-print("Document length - #tokens:", len(co.tokenize(text=long_text, model=co_model).tokens))
+print("Document length - #tokens:", len(co.tokenize(long_text)))
```
-```txt title="Output"
-PDF saved successfully to 'example.pdf'
-Document length - #tokens: 134184
-```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PDF saved successfully to 'example.pdf'
+ Document length - #tokens: 128618
+
## Summarizing the text
-```python PYTHON
+
+```python
def generate_response(message, max_tokens=300, temperature=0.2, k=0):
"""
A wrapper around the Cohere API to generate a response based on a given prompt.
@@ -170,7 +481,48 @@ def generate_response(message, max_tokens=300, temperature=0.2, k=0):
return response.text
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
# Example summary prompt.
prompt_template = """
## Instruction
@@ -183,22 +535,67 @@ Summarize the following Document in 3-5 sentences. Only answer based on the info
""".strip()
```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
If you run the cell below, an error will occur. Therefore, in the following sections, we will explore some techniques to address this limitation.
Error: :`CohereAPIError: too many tokens:`
-```python PYTHON
+
+
+
+```python
prompt = prompt_template.format(document=long_text)
# print(generate_response(message=prompt))
```
Therefore, in the following sections, we will explore some techniques to address this limitation.
-## Approach 1 - Truncate [#approach-1]
+
+# Approach 1 - Truncate
First we try to truncate the document so that it meets the length constraints. This approach is simple to implement and understand. However, it drops potentially important information contained towards the end of the document.
-```python PYTHON
+
+```python
# The new Cohere model has a context limit of 128k tokens. However, for the purpose of this exercise, we will assume a smaller context window.
# Employing a smaller context window also has the additional benefit of reducing the cost per request, especially if billed by the number of tokens.
@@ -210,49 +607,134 @@ def truncate(long: str, max_tokens: int) -> str:
This can break up sentences, passages, etc.
"""
- tokenized = co.tokenize(text=long, model=co_model).token_strings
+ tokenized = co.tokenize(long).token_strings
truncated = tokenized[:max_tokens]
short = "".join(truncated)
return short
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
short_text = truncate(long_text, MAX_TOKENS)
prompt = prompt_template.format(document=short_text)
print(generate_response(message=prompt))
```
- The document discusses the impact of a specific protein, p53, on the process of angiogenesis, which is the growth of new blood vessels. Angiogenesis plays a critical role in various physiological processes, including wound healing and embryonic development. The presence of the p53 protein can inhibit angiogenesis by regulating the expression of certain genes and proteins. This inhibition can have significant implications for tumor growth, as angiogenesis is essential for tumor progression. Therefore, understanding the role of p53 in angiogenesis can contribute to our knowledge of tumor suppression and potential therapeutic interventions.
- Additionally, the document mentions that the regulation of angiogenesis by p53 occurs independently of the protein's role in cell cycle arrest and apoptosis, which are other key functions of p53 in tumor suppression. This suggests that p53 has a complex and multifaceted impact on cellular processes.
-## Approach 2: Query Based Retrieval [#appoach-2]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The document outlines the European Union's proposed Regulation on Artificial Intelligence, aiming to establish harmonised rules for AI development and use while ensuring fundamental rights protection. It defines the scope, purposes, and risks addressed, excluding national security and military purposes. Prohibited AI practices, such as real-time biometric identification in public spaces, are detailed. The regulation proposes a risk-based approach, classifying high-risk AI systems and setting requirements for providers and deployers. It establishes governance structures and obligations for general-purpose AI models, including transparency and copyright compliance. The document also covers issues like conformity assessment, responsibilities along the AI value chain, and standardisation. The regulation aims to foster trustworthy AI while protecting public interests and fundamental rights.
+
+
+
+# Approach 2: Query Based Retrieval
In this section we present how we can leverage a query retriereval based approach to generate an answer to the following question: `Based on the document, are there any risks related to Elon Musk?`.
The solution is outlined below and can be broken down into four functional steps.
1. Chunk the text into units
-
- - Here we employ a simple chunking algorithm. More information about different chunking strategies can be found [here](TODO: link to chunking post).
+ - Here we employ a simple chunking algorithm. More information about different chunking strategies can be found [here](TODO: link to chunking post).
2. Use a ranking algorithm to rank chunks against the query
-
- - We leverage another Cohere endpoint, `co.rerank` ([docs link](https://docs.cohere.com/reference/rerank-1)), to rank each chunk against the query.
+ - We leverage another Cohere endpoint, `co.rerank` ([docs link](https://docs.cohere.com/reference/rerank-1)), to rank each chunk against the query.
3. Keep the most-relevant chunks until context limit is reached
-
- - `co.rerank` returns a relevance score, facilitating the selection of the most pertinent chunks. We can choose the most relevant chunks based on this score.
+ - `co.rerank` returns a relevance score, facilitating the selection of the most pertinent chunks. We can choose the most relevant chunks based on this score.
4. Put condensed text back in original order
- - Finally, we arrange the chosen chunks in their original sequence as they appear in the document.
+ - Finally, we arrange the chosen chunks in their original sequence as they appear in the document.
See `query_based_retrieval` function for the starting point.
+
### Query based retrieval implementation
-```python PYTHON
+
+```python
+############################################################
+#
+# Utility functions for chunking
+#
+############################################################
def split_text_into_sentences(text) -> List[str]:
"""
Split the input text into a list of sentences.
@@ -283,7 +765,48 @@ def build_simple_chunks(text, n_sentences=5):
return chunks
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
sentences = split_text_into_sentences(long_text)
passages = group_sentences_into_passages(sentences, n_sentences_per_passage=5)
print('Example sentence:', np.random.choice(np.asarray(sentences), size=1, replace=False))
@@ -291,13 +814,53 @@ print()
print('Example passage:', np.random.choice(np.asarray(passages), size=1, replace=False))
```
-```txt title="Output"
-Example sentence: ['4.']
-Example passage: ['T echnical robustness and safety means that AI systems are developed and used in a way that allows robustness in case of problems and resilience against attempts to alter the use or performance of the AI system so as to allow unlawful use by third parties, a nd minimise unintended harm. Privacy and data governance means that AI systems are developed and used in compliance with existing privacy and data protection rules, while processing data that meets high standards in terms of quality and integrity. Transpar ency means that AI systems are developed and used in a way that allows appropriate traceability and explainability, while making humans aware that they communicate or interact with an AI system, as well as duly informing deployers of the capabilities and l imitations of that AI system and affected persons about their rights. Diversity, non - discrimination and fairness means that AI systems are developed and used in a way that includes diverse actors and promotes equal access, gender equality and cultural dive rsity, while avoiding discriminatory impacts and unfair biases that are prohibited by Union or national law. Social and environmental well - being means that AI systems are developed and used in a sustainable and environmentally friendly manner as well as in a way to benefit all human beings, while monitoring and assessing the long - term impacts on the individual, society and democracy. ']
-```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Example sentence: ['This is to ensure that the deployer is aware and takes them into acc ount when using the high - risk AI system.']
+
+ Example passage: ['Notified bodies shall have procedures for the performance of activities which take due account of the size of an undertaking, th e sector in which it operates, its structure, the degree of complexity of the AI system in question. 8. Notified bodies shall take out appropriate liability insurance for their conformity assessment activities, unless liability is assumed by the Member Sta te in which they are established in accordance with national law or that Member State is itself directly responsible for the conformity assessment. 9. Notified bodies shall be capable of carrying out all the tasks falling to them under this Regulation with the highest degree of professional integrity and the requisite competence in the specific field, whether those tasks are carried out by notified bodies themselves or on their behalf and under their responsibility. ']
+
+
+
+```python
def _add_chunks_by_priority(
chunks: List[str],
idcs_sorted_by_priority: List[int],
@@ -317,7 +880,7 @@ def _add_chunks_by_priority(
while num_tokens < max_tokens and len(idcs_queue) > 0:
next_idx = idcs_queue.popleft()
- num_tokens += len(co.tokenize(text=chunks[next_idx], model=co_model).tokens)
+ num_tokens += co.tokenize(chunks[next_idx]).length
# keep index and chunk, to reorder chronologically
selected.append((next_idx, chunks[next_idx]))
if num_tokens > max_tokens:
@@ -340,7 +903,7 @@ def query_based_retrieval(
# 2. Use co.rerank to rank chunks vs. query
chunks_reranked = co.rerank(query=query, documents=chunks, model="rerank-english-v3.0")
idcs_sorted_by_relevance = [
- chunk.index for chunk in sorted(chunks_reranked.results, key=lambda c: c.relevance_score, reverse=True)
+ chunk.index for chunk in sorted(chunks_reranked, key=lambda c: c.relevance_score, reverse=True)
]
# 3. Add chunks back in order of relevance
@@ -352,7 +915,48 @@ def query_based_retrieval(
return short
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
# Example prompt
prompt_template = """
## Instruction
@@ -365,49 +969,136 @@ prompt_template = """
""".strip()
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
query = "What does the report say about biometric identification? Answer only based on the document."
short_text = query_based_retrieval(long_text, MAX_TOKENS, query)
prompt = prompt_template.format(query=query, document=short_text)
print(generate_response(message=prompt, max_tokens=300))
```
-```txt title="Output"
-The report discusses the restrictions on the use of biometric identification by law enforcement in publicly accessible spaces. According to the document, real-time biometric identification is prohibited unless in exceptional cases where its use is strictly necessary and proportionate to achieving a substantial public interest. The use of post-remote biometric identification systems is also mentioned, noting the requirements for authorization and limitations on its use.
-The report also highlights the classification of certain AI systems as high-risk, including biometric identification systems, emotion recognition systems, and biometric categorisation systems, with the exception of systems used for biometric verification. High-risk AI systems are subject to specific requirements and obligations.
-```
-## Approach 3: Text rank [#approach-3]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The report discusses the regulation of biometric identification, specifically the use of real-time systems in publicly accessible spaces for law enforcement purposes. The use of these systems is generally prohibited except in certain circumstances, such as searching for missing people or identifying perpetrators of serious criminal offences.
+
+ The report outlines a number of exceptions and additional prohibitions related to biometric identification. For instance, biometric categorisation based on specific beliefs or characteristics is generally prohibited, along with untargeted scraping of facial images for creating facial recognition databases.
+
+ Additionally, the document mentions post-remote biometric identification, which is subject to additional safeguards. These include authorisation requirements and restrictions on their use for law enforcement purposes.
+
+ The regulation also addresses the accuracy, robustness and cybersecurity of AI systems, including high-risk systems that involve biometric identification. Providers of such systems are responsible for ensuring compliance with these requirements.
+
+ National competent authorities and market surveillance authorities are designated to oversee the implementation of these regulations. They have the power to enforce compliance, including the imposition of penalties for non-compliance.
+
+ Overall, the report aims to establish a uniform legal framework for AI systems, especially those involving biometric identification, while ensuring the protection of fundamental rights and individual freedoms.
+
+
+
+# Approach 3: Text rank
In the final section we will show how we leverage graph theory to select chunks based on their centrality. Centrality is a graph-theoretic measure of how connected a node is; the higher the centrality, the more connected the node is to surrounding nodes (with fewer connections among those neighbors).
The solution presented in this document can be broken down into five functional steps:
1. Break the document into chunks.
-
- - This mirrors the first step in [Approach 2](#approach-2).
+ - This mirrors the first step in [Approach 2](#query-based-retrieval).
2. Embed each chunk using an embedding model and construct a similarity matrix.
-
- - We utilize `co.embed` [documentation link](https://docs.cohere.com/reference/embed).
+ - We utilize `co.embed` [documentation link](https://docs.cohere.com/reference/embed).
3. Compute the centrality of each chunk.
-
- - We employ a package called [`NetworkX`](https://networkx.org/documentation/networkx-1.10/overview.html). It constructs a graph where the chunks are nodes, and the similarity score between them serves as the weight of the edges. Then, we calculate the centrality of each chunk as the sum of the edge weights adjacent to the node representing that chunk.
+ - We employ a package called [`NetworkX`](https://networkx.org/documentation/networkx-1.10/overview.html). It constructs a graph where the chunks are nodes, and the similarity score between them serves as the weight of the edges. Then, we calculate the centrality of each chunk as the sum of the edge weights adjacent to the node representing that chunk.
4. Retain the highest-centrality chunks until the context limit is reached.
-
- - This step follows a similar approach to [Approach 2](#approach-2).
+ - This step follows a similar approach to [Approach 2](#query-based-retrieval).
5. Reassemble the shortened text by reordering chunks in their original order.
- - This step mirrors the last step in [Approach 2](#approach-2).
+ - This step mirrors the last step in [Approach 2](#query-based-retrieval).
See `text_rank` as the starting point.
+
### Text rank implementation
-```python PYTHON
+
+```python
def text_rank(text: str, max_tokens: int, n_setences_per_passage: int) -> str:
"""
Shortens text by extracting key units of text from it based on their centrality.
@@ -442,7 +1133,48 @@ def text_rank(text: str, max_tokens: int, n_setences_per_passage: int) -> str:
return short
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
# Example summary prompt.
prompt_template = """
## Instruction
@@ -455,16 +1187,101 @@ Summarize the following Document in 3-5 sentences. Only answer based on the info
""".strip()
```
-```python PYTHON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```python
short_text = text_rank(long_text, MAX_TOKENS, 5)
prompt = prompt_template.format(document=short_text)
print(generate_response(message=prompt, max_tokens=600))
```
-```txt title="Output"
-The document outlines the requirements and obligations for developing and deploying AI systems in the European Union. It aims to establish a regulatory framework to foster innovation while ensuring the protection of fundamental rights and public interests. The regulation applies to providers and deployers of AI systems, including those established outside the EU. High-risk AI systems are subject to specific requirements, such as risk management, data governance, and transparency. Providers must ensure compliance and keep records, and deployers must use AI systems responsibly. The regulation also establishes an AI Office, advisory bodies, and a database for high-risk AI systems. Additionally, it addresses issues like testing, codes of conduct, and cooperation with third countries. Fines and penalties are proposed for non-compliance.
-```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The document outlines the European Union's Artificial Intelligence Act, which aims to regulate AI systems and models while promoting innovation. It establishes rules for developing, using, and monitoring AI, especially high-risk systems, to protect public interests and fundamental rights. The Act mandates risk management systems, data governance requirements, and transparency measures for high-risk AI. It also sets obligations for providers and deployers, including registration, and empowers competent authorities to enforce compliance. Additionally, it encourages codes of conduct and provides for AI regulatory sandboxes to support innovation. The EU will establish a database for high-risk AI systems, and the Commission will coordinate enforcement and promote best practices. Fines and penalties are proposed for non-compliance. The Act seeks to balance AI development and oversight, ensuring trustworthy and responsible use while fostering the EU's AI ecosystem.
+
## Summary
-In this notebook we present three useful methods to over come the limitations of context window size. In the following [blog post](https://docs.cohere.com/page/chunking-strategies), we talk more about how these methods can be evaluated.
+In this notebook we present three useful methods to over come the limitations of context window size. In the following [blog post](TODO:add link), we talk more about how these methods can be evaluated.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/migrating-prompts.mdx b/fern/pages/cookbooks/migrating-prompts.mdx
index ea750d4a9..5a225683f 100644
--- a/fern/pages/cookbooks/migrating-prompts.mdx
+++ b/fern/pages/cookbooks/migrating-prompts.mdx
@@ -3,14 +3,17 @@ title: Migrating Monolithic Prompts to Command-R with RAG
slug: /page/migrating-prompts
description: "This page contains a discussion of how to automatically migrating monolothic prompts."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, prompt engineering"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
Command-R is a powerful LLM optimized for long context tasks such as retrieval augmented generation (RAG). Migrating a monolithic task such as question-answering or query-focused summarization to RAG can improve the quality of responses due to reduced hallucination and improved conciseness through grounding.
@@ -23,11 +26,14 @@ The two use cases demonstrated here are:
1. Autobiography Assistant; and
2. Legal Question Answering
-```python PYTHON
+
+```python
+# Start by installing the Cohere API
#!pip install cohere
```
-```python PYTHON
+
+```python
import json
import os
import re
@@ -36,23 +42,25 @@ import cohere
import getpass
```
-```python PYTHON
+
+```python
CO_API_KEY = getpass.getpass('cohere API key:')
```
-```txt title="Output"
-cohere API key:··········
-```
+ cohere API key:··········
-```python PYTHON
+
+
+```python
co = cohere.Client(CO_API_KEY)
```
## Autobiography Assistant
-This application scenario is a common LLM-as-assistant use case: given some context, help the user to complete a task. In this case, the task is to write a concise autobiographical summary.
+This application scenario is a common LLM-as-assistant use case. Given some context, help the user to complete a task. In this case, the task is to write a concise autobiographical summary.
+
-```python PYTHON
+```python
original_prompt = '''## information
Current Job Title: Senior Software Engineer
Current Company Name: GlobalSolTech
@@ -68,24 +76,26 @@ The length of the text should be no more than 100 words.
Write the summary in first person.'''
```
-```python PYTHON
+
+```python
response = co.chat(
message=original_prompt,
model='command-r',
)
```
-```python PYTHON
+
+```python
print(response.text)
```
-```txt
I'm a Senior Software Engineer at GlobalSolTech, with over 15 years of experience in AI and machine learning. My expertise lies in developing innovative algorithms for natural language processing, computer vision, and recommendation systems. I hold a B.Sc. in Physics and a Ph.D. in Statistics and enjoy hiking, free diving, and collecting vintage watches in my spare time. I'm passionate about using my skills to contribute to cutting-edge AI research and development. At GlobalSolTech, I'm proud to be part of a dynamic team driving technological advancement.
-```
+
Using Command-R, we can automatically upgrade the original prompt to a RAG-style prompt to get more faithful adherence to the instructions, a clearer and more concise prompt, and in-line citations for free. Consider the following meta-prompt:
-```python PYTHON
+
+```python
meta_prompt = f'''Below is a task for an LLM delimited with ## Original Task. Your task is to split that task into two parts: (1) the context; and (2) the instructions.
The context should be split into several separate parts and returned as a JSON object where each part has a name describing its contents and the value is the contents itself.
Make sure to include all of the context contained in the original task description and do not change its meaning.
@@ -93,8 +103,8 @@ The instructions should be re-written so that they are very clear and concise. D
Return everything in a JSON object with the following structure:
{{
- "context": [{{"": ""}}, ...],
- "instructions": ""
+ "context": [{{"": ""}}, ...],
+ "instructions": ""
}}
## Original Task
@@ -102,77 +112,80 @@ Return everything in a JSON object with the following structure:
'''
```
-```python PYTHON
+
+```python
print(meta_prompt)
```
-```txt title="Output"
-Below is a task for an LLM delimited with ## Original Task. Your task is to split that task into two parts: (1) the context; and (2) the instructions.
-The context should be split into several separate parts and returned as a JSON object where each part has a name describing its contents and the value is the contents itself.
-Make sure to include all of the context contained in the original task description and do not change its meaning.
-The instructions should be re-written so that they are very clear and concise. Do not change the meaning of the instructions or task, just make sure they are very direct and clear.
-Return everything in a JSON object with the following structure:
-
-{
- "context": [{"": ""}, ...],
- "instructions": ""
-}
-
-## Original Task
-## information
-Current Job Title: Senior Software Engineer
-Current Company Name: GlobalSolTech
-Work Experience: Over 15 years of experience in software engineering, specializing in AI and machine learning. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems.
-Current Department Name: AI Research and Development
-Education: B.Sc. in Physics from Trent University (2004), Ph.D. in Statistics from HEC in Paris (2010)
-Hobbies: I love hiking in the mountains, free diving, and collecting and restoring vintage world war one mechanical watches.
-Family: Married with 4 children and 3 grandchildren.
+ Below is a task for an LLM delimited with ## Original Task. Your task is to split that task into two parts: (1) the context; and (2) the instructions.
+ The context should be split into several separate parts and returned as a JSON object where each part has a name describing its contents and the value is the contents itself.
+ Make sure to include all of the context contained in the original task description and do not change its meaning.
+ The instructions should be re-written so that they are very clear and concise. Do not change the meaning of the instructions or task, just make sure they are very direct and clear.
+ Return everything in a JSON object with the following structure:
+
+ {
+ "context": [{"": ""}, ...],
+ "instructions": ""
+ }
+
+ ## Original Task
+ ## information
+ Current Job Title: Senior Software Engineer
+ Current Company Name: GlobalSolTech
+ Work Experience: Over 15 years of experience in software engineering, specializing in AI and machine learning. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems.
+ Current Department Name: AI Research and Development
+ Education: B.Sc. in Physics from Trent University (2004), Ph.D. in Statistics from HEC in Paris (2010)
+ Hobbies: I love hiking in the mountains, free diving, and collecting and restoring vintage world war one mechanical watches.
+ Family: Married with 4 children and 3 grandchildren.
+
+ ## instructions
+ Your task is to assist a user in writing a short biography for social media.
+ The length of the text should be no more than 100 words.
+ Write the summary in first person.
+
-## instructions
-Your task is to assist a user in writing a short biography for social media.
-The length of the text should be no more than 100 words.
-Write the summary in first person.
-```
Command-R returns with the following:
-```python PYTHON
+
+```python
upgraded_prompt = co.chat(
message=meta_prompt,
model='command-r',
)
```
-```python PYTHON
+
+```python
print(upgraded_prompt.text)
```
-````txt title="Output"
-Here is the task delved into a JSON object as requested:
-```json JSON
-{
- "context": [
- {
- "Work Experience": "Over 15 years of AI and machine learning engineering experience. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems."
- },
+ Here is the task delved into a JSON object as requested:
+ ```json
{
- "Education": "B.Sc. in Physics (Trent University, 2004) and Ph.D. in Statistics (HEC Paris, 2010)."
- },
- {
- "Personal Life": "I’m a married senior software engineer with 4 children and 3 grandchildren. I enjoy hiking, free diving, and vintage watch restoration."
- },
- {
- "Current Position": "I work at GlobalSolTech in the AI Research and Development department as a senior software engineer."
+ "context": [
+ {
+ "Work Experience": "Over 15 years of AI and machine learning engineering experience. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems."
+ },
+ {
+ "Education": "B.Sc. in Physics (Trent University, 2004) and Ph.D. in Statistics (HEC Paris, 2010)."
+ },
+ {
+ "Personal Life": "I’m a married senior software engineer with 4 children and 3 grandchildren. I enjoy hiking, free diving, and vintage watch restoration."
+ },
+ {
+ "Current Position": "I work at GlobalSolTech in the AI Research and Development department as a senior software engineer."
+ }
+ ],
+ "instructions": "Using the provided information, write a concise, first-person social media biography of no more than 100 words."
}
- ],
- "instructions": "Using the provided information, write a concise, first-person social media biography of no more than 100 words."
-}
-```
-````
+ ```
+
To extract the returned information, we will write two simple functions to post-process out the JSON and then parse it.
-````python PYTHON
+
+```python
def get_json(text: str) -> str:
matches = [m.group(1) for m in re.finditer("```([\w\W]*?)```", text)]
if len(matches):
@@ -181,9 +194,10 @@ def get_json(text: str) -> str:
return postproced[4:]
return postproced
return text
-````
+```
+
-```python PYTHON
+```python
def get_prompt_and_docs(text: str) -> tuple:
json_obj = json.loads(get_json(text))
prompt = json_obj['instructions']
@@ -194,29 +208,35 @@ def get_prompt_and_docs(text: str) -> tuple:
return prompt, docs
```
-```python PYTHON
+
+```python
new_prompt, docs = get_prompt_and_docs(upgraded_prompt.text)
```
-```python PYTHON
+
+```python
new_prompt, docs
```
-```txt title="Output"
-('Using the provided information, write a concise, first-person social media biography of no more than 100 words.',
- [{'title': 'Work Experience',
- 'snippet': 'Over 15 years of AI and machine learning engineering experience. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems.'},
- {'title': 'Education',
- 'snippet': 'B.Sc. in Physics (Trent University, 2004) and Ph.D. in Statistics (HEC Paris, 2010).'},
- {'title': 'Personal Life',
- 'snippet': 'I’m a married senior software engineer with 4 children and 3 grandchildren. I enjoy hiking, free diving, and vintage watch restoration.'},
- {'title': 'Current Position',
- 'snippet': 'I work at GlobalSolTech in the AI Research and Development department as a senior software engineer.'}])
-```
+
+
+
+ ('Using the provided information, write a concise, first-person social media biography of no more than 100 words.',
+ [{'title': 'Work Experience',
+ 'snippet': 'Over 15 years of AI and machine learning engineering experience. Proficient in Python, C++, and Java, with expertise in developing algorithms for natural language processing, computer vision, and recommendation systems.'},
+ {'title': 'Education',
+ 'snippet': 'B.Sc. in Physics (Trent University, 2004) and Ph.D. in Statistics (HEC Paris, 2010).'},
+ {'title': 'Personal Life',
+ 'snippet': 'I’m a married senior software engineer with 4 children and 3 grandchildren. I enjoy hiking, free diving, and vintage watch restoration.'},
+ {'title': 'Current Position',
+ 'snippet': 'I work at GlobalSolTech in the AI Research and Development department as a senior software engineer.'}])
+
+
As we can see above, the new prompt is much more concise and gets right to the point. The context has been split into 4 "documents" that Command-R can ground the information to. Now let's run the same task with the new prompt while leveraging the `documents=` parameter. Note that the `docs` variable is a list of dict objects with `title` describing the contents of a text and `snippet` containing the text itself:
-```python PYTHON
+
+```python
response = co.chat(
message=new_prompt,
model='command-r',
@@ -224,17 +244,18 @@ response = co.chat(
)
```
-```python PYTHON
+
+```python
print(response.text)
```
-```txt title="Output"
-I'm a senior software engineer with a Ph.D. in Statistics and over 15 years of AI and machine learning engineering experience. My current focus at GlobalSolTech's AI R&D department is developing algorithms for natural language processing, computer vision, and recommendation systems. In my free time, I enjoy hiking, freediving, and restoring vintage watches, and I'm a married father of four with three grandchildren.
-```
+ I'm a senior software engineer with a Ph.D. in Statistics and over 15 years of AI and machine learning engineering experience. My current focus at GlobalSolTech's AI R&D department is developing algorithms for natural language processing, computer vision, and recommendation systems. In my free time, I enjoy hiking, freediving, and restoring vintage watches, and I'm a married father of four with three grandchildren.
+
The response is concise. More importantly, we can ensure that there is no hallucination because the text is automatically grounded in the input documents. Using the simple function below, we can add this grounding information to the text as citations:
-```python PYTHON
+
+```python
def insert_citations(text: str, citations: list[dict], add_one: bool=False):
"""
A helper function to pretty print citations.
@@ -263,49 +284,59 @@ def insert_citations(text: str, citations: list[dict], add_one: bool=False):
return text
```
-```python PYTHON
+
+```python
print(insert_citations(response.text, response.citations, True))
```
-```txt title="Output"
-I'm a senior software engineer [3, 4] with a Ph.D. in Statistics [2] and over 15 years of AI and machine learning engineering experience. [1] My current focus at GlobalSolTech's AI R&D department [4] is developing algorithms for natural language processing, computer vision, and recommendation systems. [1] In my free time, I enjoy hiking, freediving, and restoring vintage watches [3], and I'm a married father of four with three grandchildren. [3]
-```
+ I'm a senior software engineer [3, 4] with a Ph.D. in Statistics [2] and over 15 years of AI and machine learning engineering experience. [1] My current focus at GlobalSolTech's AI R&D department [4] is developing algorithms for natural language processing, computer vision, and recommendation systems. [1] In my free time, I enjoy hiking, freediving, and restoring vintage watches [3], and I'm a married father of four with three grandchildren. [3]
+
Now let's move on to an arguably more difficult problem.
## Legal Question Answering
-On March 21st, the DOJ announced that it is [suing Apple](https://www.theverge.com/2024/3/21/24107659/apple-doj-lawsuit-antitrust-documents-suing) for anti-competitive practices. The [complaint](https://www.justice.gov/opa/media/1344546/dl) is 88 pages long and consists of about 230 paragraphs of text. To understand what the suit alleges, a common use case would be to ask for a summary. Because Command-R has a context window of 128K, even an 88-page legal complaint fits comfortably within the window.
+On March 21st, the DOJ announced that it is [suing apple](https://www.theverge.com/2024/3/21/24107659/apple-doj-lawsuit-antitrust-documents-suing) for anti-competitive practices. The [complaint](https://www.justice.gov/opa/media/1344546/dl) is 88 pages long and consists of about 230 paragraphs of text. To understand what the suit alleges, a common use case would be to ask for a summary. Because Command-R has a context window of 128K, even an 88-page legal complaint fits comfortably within the window.
-```python PYTHON
+
+```python
apple = open('data/apple_mod.txt').read()
```
-```python PYTHON
+
+```python
tokens = co.tokenize(text=apple, model='command-r')
len(tokens.tokens)
```
-```txt title="Output"
-29697
-```
+
+
+
+ 29697
+
+
We can set up a prompt template that allows us to ask questions on the original text.
-```python PYTHON
+
+```python
prompt_template = '''
+# Legal Text
{legal_text}
+# Question
{question}
'''
```
-```python PYTHON
+
+```python
question = '''Please summarize the attached legal complaint succinctly. Focus on answering the question: what does the complaint allege?'''
rendered_prompt = prompt_template.format(legal_text=apple, question=question)
```
-```python PYTHON
+
+```python
response = co.chat(
message=rendered_prompt,
model='command-r',
@@ -313,41 +344,44 @@ response = co.chat(
)
```
-```python PYTHON
+
+```python
print(response.text)
```
-```txt title="Output"
-The complaint alleges that Apple has violated antitrust laws by engaging in a pattern of anticompetitive conduct to maintain its monopoly power over the U.S. markets for smartphones and performance smartphones. Apple is accused of using its control over app distribution and access to its operating system to impede competition and innovation. Specifically, the company is said to have restricted developers' ability to create certain apps and limited the functionality of others, making it harder for consumers to switch away from iPhones to rival smartphones. This conduct is alleged to have harmed consumers and developers by reducing choice, increasing prices, and stifling innovation. The plaintiffs seek injunctive relief and potential monetary awards to remedy these illegal practices.
-```
+ The complaint alleges that Apple has violated antitrust laws by engaging in a pattern of anticompetitive conduct to maintain its monopoly power over the U.S. markets for smartphones and performance smartphones. Apple is accused of using its control over app distribution and access to its operating system to impede competition and innovation. Specifically, the company is said to have restricted developers' ability to create certain apps and limited the functionality of others, making it harder for consumers to switch away from iPhones to rival smartphones. This conduct is alleged to have harmed consumers and developers by reducing choice, increasing prices, and stifling innovation. The plaintiffs seek injunctive relief and potential monetary awards to remedy these illegal practices.
-The summary seems clear enough. But we are interested in the specific allegations that the DOJ makes. For example, skimming the full complaint, it looks like the DOJ is alleging that Apple could encrypt text messages sent to Android phones if it wanted to do so. We can amend the rendered prompt and ask:
-```python PYTHON
+The summary seems clear enough. But I am interested in the specific allegations that the DOJ makes. For example, skimming the full complaint, it looks like the DOJ is alleging that Apple could encrypt text messages sent to Android phones if it wanted to do so. We can ammend the rendered prompt and ask:
+
+
+```python
question = '''Does the DOJ allege that Apple could encrypt text messages sent to Android phones?'''
rendered_prompt = prompt_template.format(legal_text=apple, question=question)
```
-```python PYTHON
+
+```python
response = co.chat(
message=rendered_prompt,
model='command-r',
)
```
-```python PYTHON
+
+```python
print(response.text)
```
-```txt title="Output"
-Yes, the DOJ alleges that Apple could allow iPhone users to send encrypted messages to Android users while still using iMessage on their iPhones but chooses not to do so. According to the DOJ, this would instantly improve the privacy and security of iPhones and other smartphones.
-```
+ Yes, the DOJ alleges that Apple could allow iPhone users to send encrypted messages to Android users while still using iMessage on their iPhones but chooses not to do so. According to the DOJ, this would instantly improve the privacy and security of iPhones and other smartphones.
+
This is a very interesting allegation that at first glance suggests that the model could be hallucinating. Because RAG has been shown to help reduce hallucinations and grounds its responses in the input text, we should convert this prompt to the RAG style paradigm to gain confidence in its response.
While previously we asked Command-R to chunk the text for us, the legal complaint is highly structured with numbered paragraphs so we can use the following function to break the complaint into input docs ready for RAG:
-```python PYTHON
+
+```python
def chunk_doc(input_doc: str) -> list:
chunks = []
current_para = 'Preamble'
@@ -370,21 +404,24 @@ def chunk_doc(input_doc: str) -> list:
return docs
```
-```python PYTHON
+
+```python
chunks = chunk_doc(apple)
```
-```python PYTHON
+
+```python
+# example: show the 18th chunk
print(chunks[18])
```
-```python title="Output"
{'title': '18', 'snippet': '\nProtecting competition and the innovation that competition inevitably ushers in\nfor consumers, developers, publishers, content creators, and device manufacturers is why\nPlaintiffs bring this lawsuit under Section 2 of the Sherman Act to challenge Apple’s\nmaintenance of its monopoly over smartphone markets, which affect hundreds of millions of\nAmericans every day. Plaintiffs bring this case to rid smartphone markets of Apple’s\nmonopolization and exclusionary conduct and to ensure that the next generation of innovators\ncan upend the technological world as we know it with new and transformative technologies.\n\n\nII.\n\nDefendant Apple\n\n'}
-```
+
We can now try the same question but ask it directly to Command-R with the chunks as grounding information.
-```python PYTHON
+
+```python
response = co.chat(
message='''Does the DOJ allege that Apple could encrypt text messages sent to Android phones?''',
model='command-r',
@@ -392,52 +429,65 @@ response = co.chat(
)
```
-```python PYTHON
+
+```python
print(response.text)
```
-```txt title="Output"
-Yes, according to the DOJ, Apple could encrypt text messages sent from iPhones to Android phones. The DOJ claims that Apple degrades the security and privacy of its users by impeding cross-platform encryption and preventing developers from fixing the broken cross-platform messaging experience. Apple's conduct makes it harder to switch from iPhone to Android, as messages sent from iPhones to Android phones are unencrypted.
-```
+ Yes, according to the DOJ, Apple could encrypt text messages sent from iPhones to Android phones. The DOJ claims that Apple degrades the security and privacy of its users by impeding cross-platform encryption and preventing developers from fixing the broken cross-platform messaging experience. Apple's conduct makes it harder to switch from iPhone to Android, as messages sent from iPhones to Android phones are unencrypted.
+
The responses seem similar, but we should add citations and check the citation to get confidence in the response.
-```python PYTHON
+
+```python
print(insert_citations(response.text, response.citations))
```
-```txt title="Output"
-Yes, according to the DOJ, Apple could encrypt text messages sent from iPhones to Android phones. [144] The DOJ claims that Apple degrades the security and privacy [144] of its users by impeding cross-platform encryption [144] and preventing developers from fixing the broken cross-platform messaging experience. [93] Apple's conduct makes it harder to switch from iPhone to Android [144], as messages sent from iPhones to Android phones are unencrypted. [144]
-```
+ Yes, according to the DOJ, Apple could encrypt text messages sent from iPhones to Android phones. [144] The DOJ claims that Apple degrades the security and privacy [144] of its users by impeding cross-platform encryption [144] and preventing developers from fixing the broken cross-platform messaging experience. [93] Apple's conduct makes it harder to switch from iPhone to Android [144], as messages sent from iPhones to Android phones are unencrypted. [144]
+
The most important passage seems to be paragraph 144. Paragraph 93 is also cited. Let's check what they contain.
-```python PYTHON
+
+```python
print(chunks[144]['snippet'])
```
-```txt title="Output"
-Apple is also willing to make the iPhone less secure and less private if that helps
-maintain its monopoly power. For example, text messages sent from iPhones to Android phones
-are unencrypted as a result of Apple’s conduct. If Apple wanted to, Apple could allow iPhone
-users to send encrypted messages to Android users while still using iMessage on their iPhone,
-which would instantly improve the privacy and security of iPhone and other smartphone users.
-```
+
+ Apple is also willing to make the iPhone less secure and less private if that helps
+ maintain its monopoly power. For example, text messages sent from iPhones to Android phones
+ are unencrypted as a result of Apple’s conduct. If Apple wanted to, Apple could allow iPhone
+ users to send encrypted messages to Android users while still using iMessage on their iPhone,
+ which would instantly improve the privacy and security of iPhone and other smartphone users.
+
+
+
+
-```python PYTHON
+```python
print(chunks[93]['snippet'])
```
-```txt title="Output"
-Recently, Apple blocked a third-party developer from fixing the broken cross-
-platform messaging experience in Apple Messages and providing end-to-end encryption for
-messages between Apple Messages and Android users. By rejecting solutions that would allow
-for cross-platform encryption, Apple continues to make iPhone users’ less secure than they could
-otherwise be.
+
+ Recently, Apple blocked a third-party developer from fixing the broken cross-
+ platform messaging experience in Apple Messages and providing end-to-end encryption for
+ messages between Apple Messages and Android users. By rejecting solutions that would allow
+ for cross-platform encryption, Apple continues to make iPhone users’ less secure than they could
+ otherwise be.
+
+ ii.
+
+
-ii.
-```
Paragraph 144 indeed contains the important allegation: **If Apple wanted to, Apple could allow iPhone users to send encrypted messages to Android users**.
+# Conclusion
+
In this cookbook we have shown how one can easily take an existing monolithic prompt and migrate it to the RAG paradigm to get less hallucination, grounded information, and in-line citations. We also demonstrated Command-R's ability to re-write an instruction prompt in a single shot to make it more concise and potentially lead to higher quality completions.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/multi-purpose-agent.mdx b/fern/pages/cookbooks/multi-purpose-agent.mdx
new file mode 100644
index 000000000..f005c0a31
--- /dev/null
+++ b/fern/pages/cookbooks/multi-purpose-agent.mdx
@@ -0,0 +1,720 @@
+---
+title: Agentic RAG with an Evaluator, Web Search, Human Input, and Python Tool.
+slug: /page/multi-purpose-agent
+
+description: "This page describes how to build a powerful, multi-stage agent with the Cohere platform."
+image: ""
+keywords: ""
+---
+
+import { AuthorsContainer } from "../../components/authors-container";
+import { CookbookHeader } from "../../components/cookbook-header";
+
+
+
+
+
+
+
+## Motivation
+
+Tool use enhances the capabilities of LLMs by enabling them to offload tasks that are ill-suited for next-token-prediction language modeling. Tools allow models to (indirectly) perform mathematical or other deterministic operations, run code, and search a wide array of data sources. In this notebook, we demonstrate that Cohere's Command model can be used to extend this paradigm, to encompass diverse use cases that rely on information retrieval, programming, and human input.
+
+In an enterprise setting, information is often distributed across a wide range of knowledge bases - for instance: cloud-based document repositories such as Notion, Jira, Google Drive, or Microsoft SharePoint; chat logs from Slack, Microsoft Teams and others; or meeting transcripts and internal documents. By building out bespoke tools for each knowledge base, we allow the agent to access whatever sources of information are needed for a use case.
+
+Given these results, we can then allow the agent to determine if the information retrieved is sufficient to answer the query, or if a web search is needed. Here, this is done via a modified version of the [correctness](https://github.com/run-llama/llama_index/blob/main/llama-index-core/llama_index/core/evaluation/correctness.py) evaluator template from LlamaIndex. If the score is low, the agent asks the user for permission to do a web search to find the answer.
+
+## Objective
+
+This notebook will showcase how an agent can equip LLM with multiple tools like RAG and web search to become a useful assistant.
+
+## Questions
+
+- "How much do we get for a referral?" -> HR question
+- "How do I set up api key for cohere?" -> IT Question
+- "Is cohere available on aws" -> web search question
+- "How much do I get a year on learning and development, and can you calculate how much I can spend per week?" --> HR question + Calculation
+
+## Data
+
+- Mock internal database of HR documents
+- Mock internal database of IT documents (such as API docs)
+
+## Tools
+
+- Python Interpreter
+- HR data retriever
+- IT data retriever
+- Web search tool with human permission
+
+
+
+```python
+import os
+from pprint import pprint
+
+import cohere
+import pandas as pd
+
+from langchain.agents import Tool
+from langchain_core.pydantic_v1 import BaseModel, Field
+from langchain_experimental.utilities import PythonREPL
+from sklearn.metrics.pairwise import cosine_similarity
+```
+
+
+```python
+# uncomment if you need to install the following packages
+# !pip install --quiet langchain langchain_experimental cohere --upgrade
+```
+
+
+```python
+# versions
+import langchain
+import langchain_core
+import langchain_experimental
+print('cohere version:', cohere.__version__)
+print('langchain_core version:', langchain_core.__version__)
+print('langchain_experimental version:', langchain_experimental.__version__)
+```
+
+ cohere version: 5.5.1
+ langchain_core version: 0.2.0
+ langchain_experimental version: 0.0.59
+
+
+## Setup
+
+
+
+```python
+COHERE_API_KEY = os.environ.get("COHERE_API_KEY")
+COHERE_MODEL = 'command-r-plus'
+co = cohere.Client(api_key=COHERE_API_KEY)
+```
+
+## Data
+
+Here we define HR and IT related documents, which will be used as a mock database.
+
+
+
+```python
+# generated by LLM
+hr_documents = [
+ {
+ "title": "Remote Work Policy",
+ "content": "We embrace a remote-friendly work environment, allowing employees to work remotely on a full-time or hybrid basis. However, employees should expect to come to the office once a quarter. Expectations for remote work include maintaining regular working hours, responding promptly to communications, and attending virtual meetings. We provide remote workers with the necessary equipment and reimburse expenses for setting up a home office. Virtual collaboration tools, such as video conferencing software and project management platforms, are utilized to ensure effective remote work experiences. In-person meetings and team-building activities are also organized periodically to foster connections.",
+ },
+ {
+ "title": "Global Mobility Program",
+ "content": "Employees have the opportunity to work in different countries through our Global Mobility Program. This policy outlines the process for international assignments, including permanent transfers, short-term projects, and rotational programs. We provide support with visa sponsorship, relocation assistance, and cultural integration. Compensation packages are adjusted to align with the host country's market rates, and employees are offered pre-assignment training and ongoing support during their time abroad. Reassignment back to their home country or another location is also facilitated as part of this program. ",
+ },
+ {
+ "title": "Paid Time Off and Sick Days",
+ "content": "We offer a competitive paid time off package, including vacation days, personal days, and sick leave. Employees are entitled to a set number of paid vacation days each year, which increases with tenure. Unlimited sick days are provided to ensure employees can take time off for their health and well-being. Additionally, we offer paid parental leave, bereavement leave, and volunteer time off. Our policy also outlines procedures for requesting and tracking time off, as well as guidelines for managing unused days, carry-over limits, and payout options.",
+ },
+ {
+ "title": "Learning and Development Reimbursement",
+ "content": "Employees are eligible up to $9000 per year for learning and development. Investing in our employees' growth, we offer a learning and development reimbursement policy. Employees can seek reimbursement for work-related courses, certifications, conferences, and training programs. This includes tuition fees, course materials, and travel expenses associated with attending educational events.",
+ },
+ {
+ "title": "Employee Referral Program",
+ "content": "We value employee referrals and have implemented a referral bonus program. Employees who refer successful hires are eligible for a monetary bonus upon the referred candidate's start date. Our policy outlines the bonus amounts, eligibility criteria, and the referral process. We also offer incentives for referring diverse talent and provide employees with resources and guidance on effective referral strategies, including access to networking events and referral training. We offer $5000 for every successful referral.",
+ },
+]
+
+# from https://github.com/cohere-ai/cohere-python/blob/main/README.md
+it_documents = [
+ {
+ "title": "Cohere SDK Streaming",
+ "content": """The SDK supports streaming endpoints. To take advantage of this feature for chat,
+ use `chat_stream`.
+
+ ```Python
+ import cohere
+
+ co = cohere.Client(
+ api_key="YOUR_API_KEY",
+ )
+
+ stream = co.chat_stream(
+ message="Tell me a short story"
+ )
+
+ for event in stream:
+ if event.event_type == "text-generation":
+ print(event.text, end='')
+ ```""",
+ },
+ {
+ "title": "Cohere SDK environment variable",
+ "content": """> [!TIP]
+ > You can set a system environment variable `CO_API_KEY` to avoid writing your api key within your code, e.g. add `export CO_API_KEY=theapikeyforyouraccount`
+ > in your ~/.zshrc or ~/.bashrc, open a new terminal, then code calling `cohere.Client()` will read this key.
+ """,
+ },
+]
+
+```
+
+The following function helps us to convert IT and HR documents as a pandas dataframe with embeddings.
+
+
+
+```python
+def dbify(db):
+ """
+ Convert a list of dictionaries to a pandas DataFrame and add embeddings to be used as a mock database
+ """
+ db = pd.DataFrame(db)
+ # comebine title and body
+ db["combined"] = "Title: " + db["title"] + "\n" + "Body: " + db["content"]
+ # generate embedding
+ embeddings = co.embed(
+ texts=db.combined.tolist(),
+ model="embed-english-v3.0",
+ input_type="search_document",
+ )
+ db["embeddings"] = embeddings.embeddings
+ return db
+
+
+db_it = dbify(it_documents)
+db_hr = dbify(hr_documents)
+
+```
+
+## Tools
+
+Define tools that are used by the agent.
+
+
+### Retriever tools
+
+Define tools related to retrieval:
+
+- evaluator: evaluates the quality of the retrieved document.
+- web_search: performs web search given query.
+- retrieve_documents: retrieves top matching documents from a database.
+
+
+
+```python
+def evaluator(query, retrieved_documents):
+ criteria = """
+ You are an expert evaluation system for a question answering chatbot.
+
+ You are given the following information:
+ - a user query, and
+ - a generated answer
+
+ Your job is to judge the relevance and correctness of the generated answer.
+ Output a single score that represents a holistic evaluation.
+ You must return your response in a line with only the score.
+ Do not return answers in any other format.
+
+ Follow these guidelines for scoring:
+ - Your score has to be between 1 and 5, where 1 is the worst and 5 is the best.
+ - If the generated answer is not relevant to the user query, \
+ you should give a score of 1.
+ - If the generated answer is relevant but does not fully answer the question, \
+ you should give a score between 2 and 3.
+ - If the generated answer is relevant and fully correct, \
+ you should give a score between 4 and 5.
+ """
+
+ prompt = f"""
+ ## User Query
+ {query}
+
+ ## Retrieved Documents
+ {retrieved_documents}
+
+ ## Criteria
+ {criteria}
+
+ ## Output format
+ Ouput a single score that represents a holistic evaluation.
+ """
+ return co.chat(message=prompt, model=COHERE_MODEL, preamble=None).text
+
+
+def web_search(query):
+ """
+ Function to search the web for a given query.
+ """
+ question = "I could not find relevant information in the database. Do you want me to search the web? \nPlease enter 'y' or 'n':"
+
+ while True:
+ response = input(question)
+ if response == "y":
+ print("You entered 'y'.")
+ response = co.chat(
+ message=query,
+ connectors=[{"id": "web-search"}],
+ )
+ return {"web_result": response.text}
+ elif response == "n":
+ print("You entered 'n'.")
+ return {
+ "result": "User declined to search the web. Complete the conversation."
+ }
+ else:
+ print("Invalid input. Please enter 'y' or 'n'.")
+
+
+def retrieve_documents(query: str, db, n):
+ """
+ Function to retrieve most relevant documents a given query.
+ """
+
+ query_emb = co.embed(
+ texts=[query], model="embed-english-v3.0", input_type="search_query"
+ )
+
+ similarity_scores = cosine_similarity(
+ [query_emb.embeddings[0]], db.embeddings.tolist()
+ )
+ similarity_scores = similarity_scores[0]
+
+ top_indices = similarity_scores.argsort()[::-1][:n]
+ top_matches = db.iloc[top_indices]
+
+ evaluator_score = float(evaluator(query, top_matches.combined.tolist()))
+
+ if evaluator_score >= 4:
+ status_message = "Success: Retrieved documents are relevant and correct. Please answer user's question."
+ else:
+ status_message = (
+ "Warning: Retrieved documents are not relevant, please search the web."
+ )
+
+ return {
+ "top_matched_document": top_matches.combined,
+ "evaluator_score": evaluator_score,
+ "status_message": status_message,
+ }
+
+
+def retrieve_it_documents(query: str, db=db_it, n=2) -> dict:
+ """
+ Function to retrieve most relevant documents a given query.
+ It also returns other references mentioned in the top matched documents.
+ """
+ return retrieve_documents(query, db, n)
+
+
+def retrieve_hr_documents(query: str, db=db_hr, n=2) -> dict:
+ """
+ Function to retrieve most relevant documents a given query.
+ It also returns other references mentioned in the top matched documents.
+ """
+ return retrieve_documents(query, db, n)
+
+```
+
+### Python tool
+
+
+
+```python
+python_repl = PythonREPL()
+python_tool = Tool(
+ name="python_repl",
+ description="Executes python code and returns the result. The code runs in a static sandbox without interactive mode, so print output or save output to a file.",
+ func=python_repl.run,
+)
+python_tool.name = "python_interpreter"
+
+
+class ToolInput(BaseModel):
+ code: str = Field(description="Python code to execute.")
+
+
+python_tool.args_schema = ToolInput
+
+
+def run_python_code(code: str) -> dict:
+ """
+ Function to run given python code
+ """
+ input_code = ToolInput(code=code)
+ return {"python_answer": python_tool.func(input_code.code)}
+
+```
+
+### Functions map
+
+Define mapping of functions and function definitions for the agent to refer.
+
+
+
+```python
+
+functions_map = {
+ "retrieve_it_documents": retrieve_it_documents,
+ "retrieve_hr_documents": retrieve_hr_documents,
+ "web_search": web_search,
+ "run_python_code": run_python_code,
+
+}
+
+tools = [
+ {
+ "name": "retrieve_it_documents",
+ "description": "given a query, retrieve documents from a database to answer user's question related to IT",
+ "parameter_definitions": {
+ "query": {
+ "description": "user's question or query",
+ "type": "str",
+ "required": True,
+ }
+ },
+ },
+ {
+ "name": "retrieve_hr_documents",
+ "description": "given a query, retrieve documents from a database to answer user's question related to HR.",
+ "parameter_definitions": {
+ "query": {
+ "description": "user's question or query",
+ "type": "str",
+ "required": True,
+ }
+ },
+ },
+ {
+ "name": "web_search",
+ "description": "Search web to answer user's queston",
+ "parameter_definitions": {
+ "query": {
+ "description": "user's question or query",
+ "type": "str",
+ "required": True,
+ }
+ },
+ },
+ {
+ "name": "run_python_code",
+ "description": "given a python code, runs it",
+ "parameter_definitions": {
+ "code": {
+ "description": "executable python code",
+ "type": "str",
+ "required": True
+ }
+ }
+ },
+
+]
+
+```
+
+## Cohere Agent
+
+Wrapper of Cohere API to handle multi step tool use.
+
+
+
+```python
+def cohere_agent(
+ message: str,
+ preamble: str,
+ tools: list[dict],
+ force_single_step=False,
+ verbose: bool = False,
+ temperature: float = 0.3,
+) -> str:
+ """
+ Function to handle multi-step tool use api.
+
+ Args:
+ message (str): The message to send to the Cohere AI model.
+ preamble (str): The preamble or context for the conversation.
+ tools (list of dict): List of tools to use in the conversation.
+ verbose (bool, optional): Whether to print verbose output. Defaults to False.
+
+ Returns:
+ str: The final response from the call.
+ """
+
+ counter = 1
+
+ response = co.chat(
+ model=COHERE_MODEL,
+ message=message,
+ preamble=preamble,
+ tools=tools,
+ force_single_step=force_single_step,
+ temperature=temperature,
+ )
+
+ if verbose:
+ print(f"\nrunning step 0.")
+ print(response.text)
+
+ while response.tool_calls:
+ tool_results = []
+
+ if verbose:
+ print(f"\nrunning step {counter}.")
+
+ for tool_call in response.tool_calls:
+ if tool_call.parameters:
+ output = functions_map[tool_call.name](**tool_call.parameters)
+ else:
+ output = functions_map[tool_call.name]()
+
+ outputs = [output]
+ tool_results.append({"call": tool_call, "outputs": outputs})
+
+ if verbose:
+ print(
+ f"= running tool {tool_call.name}, with parameters: \n{tool_call.parameters}"
+ )
+ print(f"== tool results:")
+ pprint(output)
+
+ response = co.chat(
+ model=COHERE_MODEL,
+ message="",
+ chat_history=response.chat_history,
+ preamble=preamble,
+ tools=tools,
+ force_single_step=force_single_step,
+ tool_results=tool_results,
+ temperature=temperature,
+ )
+
+ if verbose:
+ print(response.text)
+ counter += 1
+
+ return response.text
+
+```
+
+## Preamble
+
+Preamble is a system level instruction that the agent follow.
+
+
+
+```python
+preamble = """
+You are helpful assitant for employees that has access to multiple databases such as HR and IT.
+Search relevant databases first. If you cannot find relevant information, search the web.
+You may need to use python to run some code or make calculations.
+
+Walk me through each step on what you are considering and going to do.
+"""
+```
+
+## Questions
+
+List of questions to ask the agent.
+
+
+
+```python
+
+questions = [
+ "how much do we get for a referral?",
+ "how do I set up api key for cohere?",
+ "Is cohere available on aws",
+ "how much do I get a year on learning and development. and can you calculate how much I can spend per week?"
+]
+```
+
+### Question 1 - "how much do we get for a referral?"
+
+This is an HR related question, so the agent decides to search the HR database for an answer.
+
+
+
+```python
+output = cohere_agent(questions[0], preamble, tools, verbose=True)
+```
+
+
+ running step 0.
+ I will search the HR database for information about referral bonuses.
+
+ running step 1.
+ = running tool retrieve_hr_documents, with parameters:
+ {'query': 'referral bonus'}
+ == tool results:
+ {'evaluator_score': 5.0,
+ 'status_message': 'Success: Retrieved documents are relevant and correct. '
+ "Please answer user's question.",
+ 'top_matched_document': 4 Title: Employee Referral Program\nBody: We val...
+ 3 Title: Learning and Development Reimbursement\...
+ Name: combined, dtype: object}
+ Employees who refer successful hires are eligible for a $5000 bonus upon the referred candidate's start date.
+
+
+### Question 2 - "how do I set up api key for cohere?"
+
+This is an IR related question. So the agent decides to search the IR database to answer the question.
+
+
+
+```python
+output = cohere_agent(questions[1], preamble, tools, verbose=True)
+```
+
+
+ running step 0.
+ I will search the IT database for information on how to set up an API key for Cohere.
+
+ running step 1.
+ = running tool retrieve_it_documents, with parameters:
+ {'query': 'how to set up api key for cohere'}
+ == tool results:
+ {'evaluator_score': 5.0,
+ 'status_message': 'Success: Retrieved documents are relevant and correct. '
+ "Please answer user's question.",
+ 'top_matched_document': 1 Title: Cohere SDK environment variable\nBody: ...
+ 0 Title: Cohere SDK Streaming\nBody: The SDK sup...
+ Name: combined, dtype: object}
+ To set up an API key for Cohere, you can use the following code:
+ ```Python
+ import cohere
+
+ co = cohere.Client(
+ api_key="YOUR_API_KEY",
+ )```
+
+
+### Question 3 - "Is cohere available on aws"
+
+This is an IT related question, but our database does not contain the correct information. Therefore, you see that evaluator_score is very low as the retrieved documents do not contain the information to answer user question. Thus, it tries to perform web search.
+
+
+
+```python
+# gives permission to search the web
+output = cohere_agent(questions[2], preamble, tools, verbose=True)
+```
+
+
+ running step 0.
+ I will search the HR and IT databases for information on whether Cohere is available on AWS.
+
+ running step 1.
+ = running tool retrieve_it_documents, with parameters:
+ {'query': 'Is cohere available on aws?'}
+ == tool results:
+ {'evaluator_score': 1.0,
+ 'status_message': 'Warning: Retrieved documents are not relevant, please '
+ 'search the web.',
+ 'top_matched_document': 0 Title: Cohere SDK Streaming\nBody: The SDK sup...
+ 1 Title: Cohere SDK environment variable\nBody: ...
+ Name: combined, dtype: object}
+ = running tool retrieve_hr_documents, with parameters:
+ {'query': 'Is cohere available on aws?'}
+ == tool results:
+ {'evaluator_score': 1.0,
+ 'status_message': 'Warning: Retrieved documents are not relevant, please '
+ 'search the web.',
+ 'top_matched_document': 0 Title: Remote Work Policy\nBody: We embrace a ...
+ 3 Title: Learning and Development Reimbursement\...
+ Name: combined, dtype: object}
+ I could not find any relevant information in the HR and IT databases. I will now search the web to find out if Cohere is available on AWS.
+
+ running step 2.
+ You entered 'y'.
+ = running tool web_search, with parameters:
+ {'query': 'Is cohere available on aws?'}
+ == tool results:
+ {'web_result': 'Yes, Cohere is available on AWS. Developers can access a range '
+ 'of Cohere language models in a private environment via '
+ "Amazon's AWS Cloud platform. Cohere's models are supported on "
+ 'two Amazon services: Amazon SageMaker and Amazon Bedrock.'}
+ Yes, Cohere is available on AWS. Developers can access a range of Cohere language models in a private environment via Amazon's AWS Cloud platform. Cohere's models are supported on two Amazon services: Amazon SageMaker and Amazon Bedrock.
+
+
+
+```python
+# does not give permission to search the web
+output = cohere_agent(questions[2], preamble, tools, verbose=True)
+```
+
+
+ running step 0.
+ I will search the databases to see if Cohere is available on AWS.
+
+ running step 1.
+ = running tool retrieve_it_documents, with parameters:
+ {'query': 'Is cohere available on aws?'}
+ == tool results:
+ {'evaluator_score': 1.0,
+ 'status_message': 'Warning: Retrieved documents are not relevant, please '
+ 'search the web.',
+ 'top_matched_document': 0 Title: Cohere SDK Streaming\nBody: The SDK sup...
+ 1 Title: Cohere SDK environment variable\nBody: ...
+ Name: combined, dtype: object}
+ I couldn't find any relevant information in the databases. I will now search the web to see if Cohere is available on AWS.
+
+ running step 2.
+ You entered 'n'.
+ = running tool web_search, with parameters:
+ {'query': 'Is cohere available on aws?'}
+ == tool results:
+ {'result': 'User declined to search the web. Complete the conversation.'}
+ I'm sorry, I can't answer this question.
+
+
+### Question 4 - "how much do I get a year on learning and development. and can you calculate how much I can spend per week?"
+
+This is an HR related question that requires a basic calculation to answer. The agent uses the Python tool to carry out the math.
+
+
+
+```python
+output = cohere_agent(questions[3], preamble, tools, verbose=True)
+```
+
+
+ running step 0.
+ I will first search the HR database for information on how much the user gets a year on learning and development. Then, I will calculate how much they can spend per week.
+
+ running step 1.
+ = running tool retrieve_hr_documents, with parameters:
+ {'query': 'how much do I get a year on learning and development'}
+ == tool results:
+ {'evaluator_score': 5.0,
+ 'status_message': 'Success: Retrieved documents are relevant and correct. '
+ "Please answer user's question.",
+ 'top_matched_document': 3 Title: Learning and Development Reimbursement\...
+ 4 Title: Employee Referral Program\nBody: We val...
+ Name: combined, dtype: object}
+
+
+ Python REPL can execute arbitrary code. Use with caution.
+
+
+ I found that employees are eligible for up to $9000 per year for learning and development. Now, I will calculate how much they can spend per week.
+
+ running step 2.
+ = running tool run_python_code, with parameters:
+ {'code': "import math\n\n# Total amount per year\ntotal_amount = 9000\n\n# Calculate weekly amount\nweekly_amount = total_amount / 52\n\nprint(f'You can spend up to ${weekly_amount:.2f} per week on learning and development.')"}
+ == tool results:
+ {'python_answer': 'You can spend up to $173.08 per week on learning and '
+ 'development.\n'}
+ You are eligible for up to $9000 per year for learning and development. This means you can spend up to $173.08 per week.
+
+
+## Conclusion
+
+
+This notebook provides a demonstration of an agent working with a diverse set of tools. It combines search across multiple databases and the internet, with Python code execution to provide useful and accurate information to the user.
+
diff --git a/fern/pages/cookbooks/multilingual-search.mdx b/fern/pages/cookbooks/multilingual-search.mdx
index 0a7c51b25..ed34c19ac 100644
--- a/fern/pages/cookbooks/multilingual-search.mdx
+++ b/fern/pages/cookbooks/multilingual-search.mdx
@@ -3,46 +3,51 @@ title: Multilingual Search with Cohere and Langchain
slug: /page/multilingual-search
description: "This page contains a basic tutorial on how to do search across different languages with Cohere's LLM platform."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, ElasticSearch"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-**_Read the accompanying [blog post here](https://cohere.com/blog/search-cohere-langchain/)._**
+
+
+
+
+***Read the accompanying [blog post here](https://txt.cohere.ai/search-cohere-langchain/).***
This notebook contains two examples for performing multilingual search using Cohere and Langchain. Langchain is a library that assists the development of applications built on top of large language models (LLMs), such as Cohere's models.
In short, Cohere makes it easy for developers to leverage LLMs and Langchain makes it easy to build applications with these models.
We'll go through the following examples:
-
- **Example 1 - Basic Multilingual Search**
This is a simple example of multilingual search over a list of documents.
The steps in summary:
-
- Import a list of documents
- Embed the documents and store them in an index
- Enter a query
- Return the document most similar to the query
-
- **Example 2 - Search-Based Question Answering**
This example shows a more involved example where search is combined with text generation to answer questions about long-form documents.
The steps in summary:
-
- Add an article and chunk it into smaller passages
- Embed the passages and store them in an index
- Enter a question
- Answer the question based on the most relevant documents
-```python PYTHON
+
+```python
+# TODO: upgrade to "cohere>5"! pip install "cohere<5" langchain qdrant-client tfds-nightly python-dotenv > /dev/null
+```
+
+
+```python
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.llms import Cohere
from langchain.prompts import PromptTemplate
@@ -59,106 +64,118 @@ import os
dotenv.load_dotenv(".env") # Upload an '.env' file containing an environment variable named 'COHERE_API_KEY' using your Cohere API Key
```
-```txt title="Output"
-True
-```
-
+
+
+ True
+
+
+
+# Example 1 - Basic Multilingual Search
+
+
### Import a list of documents
-```python PYTHON
+
+```python
+# Import documents
import tensorflow_datasets as tfds
dataset = tfds.load('trec', split='train')
texts = [item['text'].decode('utf-8') for item in tfds.as_numpy(dataset)]
print(f"Number of documents: {len(texts)}")
```
-```txt title="Output"
-Downloading and preparing dataset 350.79 KiB (download: 350.79 KiB, generated: 636.90 KiB, total: 987.69 KiB) to /root/tensorflow_datasets/trec/1.0.0...
+ Downloading and preparing dataset 350.79 KiB (download: 350.79 KiB, generated: 636.90 KiB, total: 987.69 KiB) to /root/tensorflow_datasets/trec/1.0.0...
-Dl Completed...: 0 url [00:00, ? url/s]
+ Dl Completed...: 0 url [00:00, ? url/s]
-Dl Size...: 0 MiB [00:00, ? MiB/s]
+ Dl Size...: 0 MiB [00:00, ? MiB/s]
-Extraction completed...: 0 file [00:00, ? file/s]
+ Extraction completed...: 0 file [00:00, ? file/s]
-Generating splits...: 0%| | 0/2 [00:00, ? splits/s]
+ Generating splits...: 0%| | 0/2 [00:00, ? splits/s]
-Generating train examples...: 0%| | 0/5452 [00:00, ? examples/s]
+ Generating train examples...: 0%| | 0/5452 [00:00, ? examples/s]
-Shuffling /root/tensorflow_datasets/trec/1.0.0.incompleteWOR5EP/trec-train.tfrecord*...: 0%| | 0/54…
+ Shuffling /root/tensorflow_datasets/trec/1.0.0.incompleteWOR5EP/trec-train.tfrecord*...: 0%| | 0/54…
-Generating test examples...: 0%| | 0/500 [00:00, ? examples/s]
+ Generating test examples...: 0%| | 0/500 [00:00, ? examples/s]
-Shuffling /root/tensorflow_datasets/trec/1.0.0.incompleteWOR5EP/trec-test.tfrecord*...: 0%| | 0/500…
+ Shuffling /root/tensorflow_datasets/trec/1.0.0.incompleteWOR5EP/trec-test.tfrecord*...: 0%| | 0/500…
-Dataset trec downloaded and prepared to /root/tensorflow_datasets/trec/1.0.0. Subsequent calls will reuse this data.
-Number of documents: 5452
-```
+ Dataset trec downloaded and prepared to /root/tensorflow_datasets/trec/1.0.0. Subsequent calls will reuse this data.
+ Number of documents: 5452
+
-```python PYTHON
+
+```python
+# Print a few sample documents
random.seed(11)
for item in random.sample(texts, 5):
- print(item)
+ print(item)
```
-```txt title="Output"
-What is the starting salary for beginning lawyers ?
-Where did Bill Gates go to college ?
-What task does the Bouvier breed of dog perform ?
-What are the top boy names in the U.S. ?
-What is a female rabbit called ?
-```
+ What is the starting salary for beginning lawyers ?
+ Where did Bill Gates go to college ?
+ What task does the Bouvier breed of dog perform ?
+ What are the top boy names in the U.S. ?
+ What is a female rabbit called ?
+
### Embed the documents and store them in an index
-```python PYTHON
+
+```python
+# Define the embeddings model
embeddings = CohereEmbeddings(model = "multilingual-22-12")
+# Embed the documents and store in index
db = Qdrant.from_texts(texts, embeddings, location=":memory:", collection_name="my_documents", distance_func="Dot")
```
### Enter a query
-```python PYTHON
+
+```python
queries = ["How to get in touch with Bill Gates",
"Comment entrer en contact avec Bill Gates",
"Cara menghubungi Bill Gates"]
-queries_lang = ["English", "French", "Indonesian"]
+queries_lang = ["English", "French", "Indonesian"]
```
### Return the document most similar to the query
-```python PYTHON
+
+```python
+# Return document most similar to the query
answers = []
for query in queries:
docs = db.similarity_search(query)
answers.append(docs[0].page_content)
```
-```python PYTHON
+
+```python
+# Print the top document match for each query
for idx,query in enumerate(queries):
print(f"Query language: {queries_lang[idx]}")
print(f"Query: {query}")
@@ -166,55 +183,57 @@ for idx,query in enumerate(queries):
print("-"*20,"\n")
```
-```txt title="Output"
-Query language: English
-Query: How to get in touch with Bill Gates
-Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
---------------------
-
-Query language: French
-Query: Comment entrer en contact avec Bill Gates
-Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
---------------------
-
-Query language: Indonesian
-Query: Cara menghubungi Bill Gates
-Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
---------------------
-```
+ Query language: English
+ Query: How to get in touch with Bill Gates
+ Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
+ --------------------
+
+ Query language: French
+ Query: Comment entrer en contact avec Bill Gates
+ Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
+ --------------------
+
+ Query language: Indonesian
+ Query: Cara menghubungi Bill Gates
+ Most similar existing question: What is Bill Gates of Microsoft E-mail address ?
+ --------------------
+
-
+
+# Example 2 - Search-Based Question Answering
+
+
## Add an article and chunk it into smaller passages
-```python PYTHON
-!wget 'https://docs.google.com/uc?export=download&id=1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F' -O steve-jobs-commencement.txt
-```
+```python
+# We'll use Steve Jobs' Stanford University commencement address as the example. Link: https://news.stanford.edu/2005/06/12/youve-got-find-love-jobs-says/
-```txt title="Output"
---2023-06-08 06:11:19-- https://docs.google.com/uc?export=download&id=1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F
-Resolving docs.google.com (docs.google.com)... 74.125.200.101, 74.125.200.138, 74.125.200.102, ...
-Connecting to docs.google.com (docs.google.com)|74.125.200.101|:443... connected.
-HTTP request sent, awaiting response... 303 See Other
-Location: https://doc-0g-84-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/84t4moii9dmg08hmrh6rfpp8ecrjh6jq/1686204675000/12721472133292131824/*/1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F?e=download&uuid=a26288c7-ad0c-4707-ae0b-72cb94c224dc [following]
-Warning: wildcards not supported in HTTP.
---2023-06-08 06:11:19-- https://doc-0g-84-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/84t4moii9dmg08hmrh6rfpp8ecrjh6jq/1686204675000/12721472133292131824/*/1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F?e=download&uuid=a26288c7-ad0c-4707-ae0b-72cb94c224dc
-Resolving doc-0g-84-docs.googleusercontent.com (doc-0g-84-docs.googleusercontent.com)... 74.125.130.132, 2404:6800:4003:c01::84
-Connecting to doc-0g-84-docs.googleusercontent.com (doc-0g-84-docs.googleusercontent.com)|74.125.130.132|:443... connected.
-HTTP request sent, awaiting response... 200 OK
-Length: 11993 (12K) [text/plain]
-Saving to: ‘steve-jobs-commencement.txt’
-
-steve-jobs-commence 100%[===================>] 11.71K --.-KB/s in 0s
-
-2023-06-08 06:11:20 (115 MB/s) - ‘steve-jobs-commencement.txt’ saved [11993/11993]
+!wget 'https://docs.google.com/uc?export=download&id=1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F' -O steve-jobs-commencement.txt
```
-```python PYTHON
+ --2023-06-08 06:11:19-- https://docs.google.com/uc?export=download&id=1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F
+ Resolving docs.google.com (docs.google.com)... 74.125.200.101, 74.125.200.138, 74.125.200.102, ...
+ Connecting to docs.google.com (docs.google.com)|74.125.200.101|:443... connected.
+ HTTP request sent, awaiting response... 303 See Other
+ Location: https://doc-0g-84-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/84t4moii9dmg08hmrh6rfpp8ecrjh6jq/1686204675000/12721472133292131824/*/1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F?e=download&uuid=a26288c7-ad0c-4707-ae0b-72cb94c224dc [following]
+ Warning: wildcards not supported in HTTP.
+ --2023-06-08 06:11:19-- https://doc-0g-84-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/84t4moii9dmg08hmrh6rfpp8ecrjh6jq/1686204675000/12721472133292131824/*/1f1INWOfJrHTFmbyF_0be5b4u_moz3a4F?e=download&uuid=a26288c7-ad0c-4707-ae0b-72cb94c224dc
+ Resolving doc-0g-84-docs.googleusercontent.com (doc-0g-84-docs.googleusercontent.com)... 74.125.130.132, 2404:6800:4003:c01::84
+ Connecting to doc-0g-84-docs.googleusercontent.com (doc-0g-84-docs.googleusercontent.com)|74.125.130.132|:443... connected.
+ HTTP request sent, awaiting response... 200 OK
+ Length: 11993 (12K) [text/plain]
+ Saving to: ‘steve-jobs-commencement.txt’
+
+ steve-jobs-commence 100%[===================>] 11.71K --.-KB/s in 0s
+
+ 2023-06-08 06:11:20 (115 MB/s) - ‘steve-jobs-commencement.txt’ saved [11993/11993]
+
+
+
+
+```python
loader = TextLoader("steve-jobs-commencement.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
@@ -223,14 +242,16 @@ texts = text_splitter.split_documents(documents)
## Embed the passages and store them in an index
-```python PYTHON
+
+```python
embeddings = CohereEmbeddings(model = "multilingual-22-12")
db = Qdrant.from_documents(texts, embeddings, location=":memory:", collection_name="my_documents", distance_func="Dot")
```
## Enter a question
-```python PYTHON
+
+```python
questions = [
"What did the author liken The Whole Earth Catalog to?",
"What was Reed College great at?",
@@ -242,7 +263,10 @@ questions = [
## Answer the question based on the most relevant documents
-```python PYTHON
+
+
+```python
+# Create our own prompt template
prompt_template = """Text: {context}
@@ -255,13 +279,14 @@ PROMPT = PromptTemplate(
)
```
-```python PYTHON
+
+```python
chain_type_kwargs = {"prompt": PROMPT}
-qa = RetrievalQA.from_chain_type(llm=Cohere(model="command", temperature=0),
- chain_type="stuff",
- retriever=db.as_retriever(),
- chain_type_kwargs=chain_type_kwargs,
+qa = RetrievalQA.from_chain_type(llm=Cohere(model="command", temperature=0),
+ chain_type="stuff",
+ retriever=db.as_retriever(),
+ chain_type_kwargs=chain_type_kwargs,
return_source_documents=True)
for question in questions:
@@ -279,100 +304,100 @@ for question in questions:
print(f"{idx+1}: {source_wrapped}")
```
-```txt title="Output"
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Question: What did the author liken The Whole Earth Catalog to?
-Answer: It was sort of like Google in paperback form, 35 years before Google came along
-
-Sources:
-1: When I was young, there was an amazing publication called The Whole Earth Catalog, which was one of the bibles of my generation. It was created by a
-fellow named Stewart Brand not far from here in Menlo Park, and he brought it to life with his poetic touch. This was in the late 1960s, before
-personal computers and desktop publishing, so it was all made with typewriters, scissors and Polaroid cameras. It was sort of like Google in paperback
-form, 35 years before Google came along: It was
-2: Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the
-mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find
-yourself hitchhiking on if you were so adventurous. Beneath it were the words: “Stay Hungry. Stay Foolish.” It was their farewell message as they
-signed off. Stay Hungry. Stay Foolish. And I have always
-3: idealistic, and overflowing with neat tools and great notions.
-4: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Question: What was Reed College great at?
-Answer: Reed College was great at calligraphy instruction.
-
-Sources:
-1: Reed College at that time offered perhaps the best calligraphy instruction in the country. Throughout the campus every poster, every label on every
-drawer, was beautifully hand calligraphed. Because I had dropped out and didn’t have to take the normal classes, I decided to take a calligraphy class
-to learn how to do this. I learned about serif and sans serif typefaces, about varying the amount of space between different letter combinations,
-about what makes great typography great. It was
-2: I dropped out of Reed College after the first 6 months, but then stayed around as a drop-in for another 18 months or so before I really quit. So why
-did I drop out?
-3: never dropped out, I would have never dropped in on this calligraphy class, and personal computers might not have the wonderful typography that they
-do. Of course it was impossible to connect the dots looking forward when I was in college. But it was very, very clear looking backward 10 years
-later.
-4: OK. It was pretty scary at the time, but looking back it was one of the best decisions I ever made. The minute I dropped out I could stop taking the
-required classes that didn’t interest me, and begin dropping in on the ones that looked interesting.
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Question: What was the author diagnosed with?
-Answer: The author was diagnosed with cancer.
-
-Sources:
-1: I lived with that diagnosis all day. Later that evening I had a biopsy, where they stuck an endoscope down my throat, through my stomach and into my
-intestines, put a needle into my pancreas and got a few cells from the tumor. I was sedated, but my wife, who was there, told me that when they viewed
-the cells under a microscope the doctors started crying because it turned out to be a very rare form of pancreatic cancer that is curable with
-surgery. I had the surgery and I’m fine now.
-2: About a year ago I was diagnosed with cancer. I had a scan at 7:30 in the morning, and it clearly showed a tumor on my pancreas. I didn’t even know
-what a pancreas was. The doctors told me this was almost certainly a type of cancer that is incurable, and that I should expect to live no longer than
-three to six months. My doctor advised me to go home and get my affairs in order, which is doctor’s code for prepare to die. It means to try to tell
-your kids everything you thought you’d have the
-3: Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the
-mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find
-yourself hitchhiking on if you were so adventurous. Beneath it were the words: “Stay Hungry. Stay Foolish.” It was their farewell message as they
-signed off. Stay Hungry. Stay Foolish. And I have always
-4: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Question: What is the key lesson from this article?
-Answer: The key lesson from this article is that you have to trust that the dots will somehow connect in your future. You have to trust in something -- your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.
-
-Sources:
-1: Again, you can’t connect the dots looking forward; you can only connect them looking backward. So you have to trust that the dots will somehow connect
-in your future. You have to trust in something — your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all
-the difference in my life. My second story is about love and loss.
-2: Remembering that I’ll be dead soon is the most important tool I’ve ever encountered to help me make the big choices in life. Because almost everything
-— all external expectations, all pride, all fear of embarrassment or failure — these things just fall away in the face of death, leaving only what is
-truly important. Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are
-already naked. There is no reason not to follow your
-3: Your time is limited, so don’t waste it living someone else’s life. Don’t be trapped by dogma — which is living with the results of other people’s
-thinking. Don’t let the noise of others’ opinions drown out your own inner voice. And most important, have the courage to follow your heart and
-intuition. They somehow already know what you truly want to become. Everything else is secondary.
-4: I really didn’t know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down — that I had dropped the baton
-as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and
-I even thought about running away from the valley. But something slowly began to dawn on me — I still loved what I did. The turn of events at Apple
-had not changed that one bit. I had been rejected,
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Question: What did the article say about Michael Jackson?
-Answer: The text did not provide information about Michael Jackson.
-
-Sources:
-1: baby boy; do you want him?” They said: “Of course.” My biological mother later found out that my mother had never graduated from college and that my
-father had never graduated from high school. She refused to sign the final adoption papers. She only relented a few months later when my parents
-promised that I would someday go to college.
-2: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
-3: I really didn’t know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down — that I had dropped the baton
-as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and
-I even thought about running away from the valley. But something slowly began to dawn on me — I still loved what I did. The turn of events at Apple
-had not changed that one bit. I had been rejected,
-4: This was the closest I’ve been to facing death, and I hope it’s the closest I get for a few more decades. Having lived through it, I can now say this
-to you with a bit more certainty than when death was a useful but purely intellectual concept:
-```
+ ------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ Question: What did the author liken The Whole Earth Catalog to?
+ Answer: It was sort of like Google in paperback form, 35 years before Google came along
+
+ Sources:
+ 1: When I was young, there was an amazing publication called The Whole Earth Catalog, which was one of the bibles of my generation. It was created by a
+ fellow named Stewart Brand not far from here in Menlo Park, and he brought it to life with his poetic touch. This was in the late 1960s, before
+ personal computers and desktop publishing, so it was all made with typewriters, scissors and Polaroid cameras. It was sort of like Google in paperback
+ form, 35 years before Google came along: It was
+ 2: Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the
+ mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find
+ yourself hitchhiking on if you were so adventurous. Beneath it were the words: “Stay Hungry. Stay Foolish.” It was their farewell message as they
+ signed off. Stay Hungry. Stay Foolish. And I have always
+ 3: idealistic, and overflowing with neat tools and great notions.
+ 4: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
+ ------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ Question: What was Reed College great at?
+ Answer: Reed College was great at calligraphy instruction.
+
+ Sources:
+ 1: Reed College at that time offered perhaps the best calligraphy instruction in the country. Throughout the campus every poster, every label on every
+ drawer, was beautifully hand calligraphed. Because I had dropped out and didn’t have to take the normal classes, I decided to take a calligraphy class
+ to learn how to do this. I learned about serif and sans serif typefaces, about varying the amount of space between different letter combinations,
+ about what makes great typography great. It was
+ 2: I dropped out of Reed College after the first 6 months, but then stayed around as a drop-in for another 18 months or so before I really quit. So why
+ did I drop out?
+ 3: never dropped out, I would have never dropped in on this calligraphy class, and personal computers might not have the wonderful typography that they
+ do. Of course it was impossible to connect the dots looking forward when I was in college. But it was very, very clear looking backward 10 years
+ later.
+ 4: OK. It was pretty scary at the time, but looking back it was one of the best decisions I ever made. The minute I dropped out I could stop taking the
+ required classes that didn’t interest me, and begin dropping in on the ones that looked interesting.
+ ------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ Question: What was the author diagnosed with?
+ Answer: The author was diagnosed with cancer.
+
+ Sources:
+ 1: I lived with that diagnosis all day. Later that evening I had a biopsy, where they stuck an endoscope down my throat, through my stomach and into my
+ intestines, put a needle into my pancreas and got a few cells from the tumor. I was sedated, but my wife, who was there, told me that when they viewed
+ the cells under a microscope the doctors started crying because it turned out to be a very rare form of pancreatic cancer that is curable with
+ surgery. I had the surgery and I’m fine now.
+ 2: About a year ago I was diagnosed with cancer. I had a scan at 7:30 in the morning, and it clearly showed a tumor on my pancreas. I didn’t even know
+ what a pancreas was. The doctors told me this was almost certainly a type of cancer that is incurable, and that I should expect to live no longer than
+ three to six months. My doctor advised me to go home and get my affairs in order, which is doctor’s code for prepare to die. It means to try to tell
+ your kids everything you thought you’d have the
+ 3: Stewart and his team put out several issues of The Whole Earth Catalog, and then when it had run its course, they put out a final issue. It was the
+ mid-1970s, and I was your age. On the back cover of their final issue was a photograph of an early morning country road, the kind you might find
+ yourself hitchhiking on if you were so adventurous. Beneath it were the words: “Stay Hungry. Stay Foolish.” It was their farewell message as they
+ signed off. Stay Hungry. Stay Foolish. And I have always
+ 4: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
+ ------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ Question: What is the key lesson from this article?
+ Answer: The key lesson from this article is that you have to trust that the dots will somehow connect in your future. You have to trust in something -- your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.
+
+ Sources:
+ 1: Again, you can’t connect the dots looking forward; you can only connect them looking backward. So you have to trust that the dots will somehow connect
+ in your future. You have to trust in something — your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all
+ the difference in my life. My second story is about love and loss.
+ 2: Remembering that I’ll be dead soon is the most important tool I’ve ever encountered to help me make the big choices in life. Because almost everything
+ — all external expectations, all pride, all fear of embarrassment or failure — these things just fall away in the face of death, leaving only what is
+ truly important. Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are
+ already naked. There is no reason not to follow your
+ 3: Your time is limited, so don’t waste it living someone else’s life. Don’t be trapped by dogma — which is living with the results of other people’s
+ thinking. Don’t let the noise of others’ opinions drown out your own inner voice. And most important, have the courage to follow your heart and
+ intuition. They somehow already know what you truly want to become. Everything else is secondary.
+ 4: I really didn’t know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down — that I had dropped the baton
+ as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and
+ I even thought about running away from the valley. But something slowly began to dawn on me — I still loved what I did. The turn of events at Apple
+ had not changed that one bit. I had been rejected,
+ ------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ Question: What did the article say about Michael Jackson?
+ Answer: The text did not provide information about Michael Jackson.
+
+ Sources:
+ 1: baby boy; do you want him?” They said: “Of course.” My biological mother later found out that my mother had never graduated from college and that my
+ father had never graduated from high school. She refused to sign the final adoption papers. She only relented a few months later when my parents
+ promised that I would someday go to college.
+ 2: beautiful, historical, artistically subtle in a way that science can’t capture, and I found it fascinating.
+ 3: I really didn’t know what to do for a few months. I felt that I had let the previous generation of entrepreneurs down — that I had dropped the baton
+ as it was being passed to me. I met with David Packard and Bob Noyce and tried to apologize for screwing up so badly. I was a very public failure, and
+ I even thought about running away from the valley. But something slowly began to dawn on me — I still loved what I did. The turn of events at Apple
+ had not changed that one bit. I had been rejected,
+ 4: This was the closest I’ve been to facing death, and I hope it’s the closest I get for a few more decades. Having lived through it, I can now say this
+ to you with a bit more certainty than when death was a useful but purely intellectual concept:
+
## Questions in French
-```python PYTHON
+
+```python
questions_fr = [
"À quoi se compare The Whole Earth Catalog ?",
"Dans quoi Reed College était-il excellent ?",
@@ -382,18 +407,22 @@ questions_fr = [
]
```
-```python PYTHON
+```python
+# import langchain
+# langchain.debug = False
```
-```python PYTHON
+
+```python
+# Generate the answer given the context
chain_type_kwargs = {"prompt": PROMPT}
-qa = RetrievalQA.from_chain_type(llm=Cohere(model="command", temperature=0),
- chain_type="stuff",
- retriever=db.as_retriever(),
- chain_type_kwargs=chain_type_kwargs,
+qa = RetrievalQA.from_chain_type(llm=Cohere(model="command", temperature=0),
+ chain_type="stuff",
+ retriever=db.as_retriever(),
+ chain_type_kwargs=chain_type_kwargs,
return_source_documents=True)
for question in questions_fr:
@@ -405,25 +434,29 @@ for question in questions_fr:
print(f"Answer: {result}")
```
-```txt title="Output"
---------------------
-
-Question: À quoi se compare The Whole Earth Catalog ?
-Answer: The Whole Earth Catalog was like Google in paperback form, 35 years before Google came along.
---------------------
-
-Question: Dans quoi Reed College était-il excellent ?
-Answer: Reed College offered the best calligraphy instruction in the country.
---------------------
-
-Question: De quoi l'auteur a-t-il été diagnostiqué ?
-Answer: The author was diagnosed with a very rare form of pancreatic cancer that is curable with surgery.
---------------------
-
-Question: Quelle est la leçon clé de cet article ?
-Answer: The key lesson of this article is that remembering that you will die soon is the most important tool to help one make the big choices in life.
---------------------
+ --------------------
+
+ Question: À quoi se compare The Whole Earth Catalog ?
+ Answer: The Whole Earth Catalog was like Google in paperback form, 35 years before Google came along.
+ --------------------
+
+ Question: Dans quoi Reed College était-il excellent ?
+ Answer: Reed College offered the best calligraphy instruction in the country.
+ --------------------
+
+ Question: De quoi l'auteur a-t-il été diagnostiqué ?
+ Answer: The author was diagnosed with a very rare form of pancreatic cancer that is curable with surgery.
+ --------------------
+
+ Question: Quelle est la leçon clé de cet article ?
+ Answer: The key lesson of this article is that remembering that you will die soon is the most important tool to help one make the big choices in life.
+ --------------------
+
+ Question: Que disait l'article sur Michael Jackson ?
+ Answer: The text does not contain the answer to the question.
+
+
+
+```python
-Question: Que disait l'article sur Michael Jackson ?
-Answer: The text does not contain the answer to the question.
```
diff --git a/fern/pages/cookbooks/pdf-extractor.mdx b/fern/pages/cookbooks/pdf-extractor.mdx
index bf24e7836..ed11bb545 100644
--- a/fern/pages/cookbooks/pdf-extractor.mdx
+++ b/fern/pages/cookbooks/pdf-extractor.mdx
@@ -3,7 +3,7 @@ title: PDF Extractor with Native Multi Step Tool Use
slug: /page/pdf-extractor
description: "This page describes how to create an AI agent able to extract information from PDFs."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, PDF extraction, LLMs, AI agents"
---
@@ -14,12 +14,14 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Jason Jung",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg"
+ }
]}
/>
-
+
+
+
## Objective
@@ -27,14 +29,16 @@ Generally, users are limited to text inputs when using large language models (LL
In the directory, we have a simple_invoice.pdf file. Everytime a user uploads the document, the agent will extract key information total_amount and invoice_number and then save it as CSV which then can be used in another application. We only extract two pieces of information in this demo, but users can extend the example and extract a lot more information.
-## Steps
+## Steps
+
+* extract_pdf() function extracts text data from the PDF using [unstructured](https://unstructured.io/) package. You can use other packages like PyPDF2 as well.
+* This extracted text is added to the prompt so the model can "see" the document.
+* The agent summarizes the document and passes that information to convert_to_json() function. This function makes another call to command model to convert the summary to json output. This separation of tasks is useful when the text document is complicated and long. Therefore, we first distill the information and ask another model to convert the text into json object. This is useful so each model or agent focuses on its own task without suffering from long context.
+* Then the json object goes through a check to make sure all keys are present and gets saved as a csv file. When the document is too long or the task is too complex, the model may fail to extract all information. These checks are then very useful because they give feedback to the model so it can adjust it's parameters to retry.
+
-1. extract_pdf() function extracts text data from the PDF using [unstructured](https://unstructured.io/) package. You can use other packages like PyPDF2 as well.
-2. This extracted text is added to the prompt so the model can "see" the document.
-3. The agent summarizes the document and passes that information to convert_to_json() function. This function makes another call to command model to convert the summary to json output. This separation of tasks is useful when the text document is complicated and long. Therefore, we first distill the information and ask another model to convert the text into json object. This is useful so each model or agent focuses on its own task without suffering from long context.
-4. Then the json object goes through a check to make sure all keys are present and gets saved as a csv file. When the document is too long or the task is too complex, the model may fail to extract all information. These checks are then very useful because they give feedback to the model so it can adjust it's parameters to retry.
-```python PYTHON
+```python
import os
import cohere
@@ -43,37 +47,44 @@ import json
from unstructured.partition.pdf import partition_pdf
```
-```python PYTHON
+
+```python
# uncomment to install dependencies
# !pip install cohere unstructured
```
-```python PYTHON
+
+```python
# versions
print('cohere version:', cohere.__version__)
```
-```txt title="Output"
-cohere version: 5.5.1
-```
+ cohere version: 5.5.1
+
+
+## Setup
-## Setup
-```python PYTHON
+```python
COHERE_API_KEY = os.environ.get("CO_API_KEY")
COHERE_MODEL = 'command-r-plus'
co = cohere.Client(api_key=COHERE_API_KEY)
```
-## Data
+## Data
-The sample invoice data is from https://unidoc.io/media/simple-invoices/simple_invoice.pdf.
+The sample invoice data is from https://unidoc.io/media/simple-invoices/simple_invoice.pdf.
-## Tool
-Here we define the tool which converts summary of the pdf into json object. Then, it checks to make sure all necessary keys are present and saves it as csv.
-```python PYTHON
+
+
+## Tool
+
+Here we define the tool which converts summary of the pdf into json object. Then, it checks to make sure all necessary keys are present and saves it as csv.
+
+
+```python
def convert_to_json(text: str) -> dict:
"""
Given text files, convert to json object and saves to csv.
@@ -96,8 +107,8 @@ def convert_to_json(text: str) -> dict:
# Output format json:
{{
- "total_amount": "",
- "invoice_number": "",
+ "total_amount": "",
+ "invoice_number": "",
}}
Do not output code blocks.
@@ -125,11 +136,12 @@ def convert_to_json(text: str) -> dict:
```
-### Cohere Agent
+### Cohere Agent
-Below is a cohere agent that leverages multi-step API. It is equipped with convert_to_json tool.
+Below is a cohere agent that leverages multi-step API. It is equipped with convert_to_json tool.
-```python PYTHON
+
+```python
def cohere_agent(
message: str,
preamble: str,
@@ -215,9 +227,10 @@ def cohere_agent(
return response.text
```
-### main
+### Extract PDF
+
-```python PYTHON
+```python
def extract_pdf(path):
"""
Function to extract text from a PDF file.
@@ -259,20 +272,20 @@ pdf_extractor('simple_invoice.pdf')
```
-```txt title="Output"
-running step 0
-I will summarise the text and then use the convert_to_json tool to format the summary.
-
-running step 1
-tool_call.parameters: {'text': 'Total amount billed: $115.00\nInvoice number: 0852'}
-= running tool convert_to_json, with parameters: {'text': 'Total amount billed: $115.00\nInvoice number: 0852'}
-== tool results: [{'result': 'SUCCESS. All steps have been completed.'}]
-SUCCESS.
-Finished extracting: simple_invoice.pdf
-Please check the output below
- total_amount invoice_number
-0 $115.00 852
-```
-
-As shown above, the model first summarized the extracted pdf as `Total amount: $115.00\nInvoice number: 0852` and sent this to `conver_to_json()` function.
-`conver_to_json()` then converts it to json format and saves it into a csv file.
+
+ running step 0
+ I will summarise the text and then use the convert_to_json tool to format the summary.
+
+ running step 1
+ tool_call.parameters: {'text': 'Total amount billed: $115.00\nInvoice number: 0852'}
+ = running tool convert_to_json, with parameters: {'text': 'Total amount billed: $115.00\nInvoice number: 0852'}
+ == tool results: [{'result': 'SUCCESS. All steps have been completed.'}]
+ SUCCESS.
+ Finished extracting: simple_invoice.pdf
+ Please check the output below
+ total_amount invoice_number
+ 0 $115.00 852
+
+
+As shown above, the model first summarized the extracted pdf as `Total amount: $115.00\nInvoice number: 0852` and sent this to `conver_to_json()` function.
+`conver_to_json()` then converts it to json format and saves it into a csv file.
diff --git a/fern/pages/cookbooks/pondr.mdx b/fern/pages/cookbooks/pondr.mdx
index 96738803a..25a65442d 100644
--- a/fern/pages/cookbooks/pondr.mdx
+++ b/fern/pages/cookbooks/pondr.mdx
@@ -3,20 +3,23 @@ title: Pondr, Fostering Connection through Good Conversation
slug: /page/pondr
description: "This page contains a basic tutorial on how tplay an AI-powered version of the icebreaking game 'Pondr'."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, Pondr, AI games"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
We tend to chat all the time with friends new and olds, but often it feels like we’re just scratching at the surface, or defaulting to predictable, mundane conversations. Really good conversations — ones that introduce an element of vulnerability, spur a moment of fun, or create a deep sense of closeness — are few and far between. And when we have those types of conversations, we remember them.
Pondr is a game that turns strangers into friends, and friends into besties, by fostering connection and closeness through really good conversations. Using Cohere, Pondr generates question prompts on command that are uniquely tailored to the players’ setting. Whether you’re looking to deepen a connection with someone you’ve known forever, or you’re just hoping to become more familiar with a new friend, Pondr will help you drive the right sort of conversation.
-You can build your own version of Pondr by following these simple steps:
+You can build your own version of Pondr by following these simple steps:
1. Generate potential conversation questions
2. Rank the generated questions
@@ -24,25 +27,32 @@ You can build your own version of Pondr by following these simple steps:
In this notebook we will walk through the first two steps.
-### Setup
+### Setup
Install and import the tools we will need as well as initializing the Cohere model.
-```python PYTHON
+
+```python
+# TODO: upgrade to "cohere>5"!pip install "cohere<5"
+```
+
+
+```python
import cohere
from cohere.responses.classify import Example
import pandas as pd
```
-```python PYTHON
+
+```python
co=cohere.Client('YOUR_API_KEY')
```
-### 1. Generate Potential Conversation Questions
-
+### 1) Generate Potential Conversation Questions
Generate a list of potential conversation questions and retain the first 10.
-```python PYTHON
+
+```python
#user_input is hardcoded for this example
user_input='I am meeting up with a coworker. We are meeting at a fancy restaurant. I wanna ask some interesting questions. These questions should be deep.'
prompt=user_input+'\nHere are 10 interesting questions to ask:\n1)'
@@ -50,7 +60,8 @@ response=co.generate(model='xlarge', prompt=prompt, max_tokens=200, temperature=
response
```
-```python PYTHON
+
+```python
def generation_to_df(generation):
generation=response.split('\n')
clean_questions=[]
@@ -61,57 +72,60 @@ def generation_to_df(generation):
return clean_q_df
```
-```python PYTHON
+
+```python
clean_q_df = generation_to_df(response)
pd.options.display.max_colwidth=150
clean_q_df
```
-### 2. Classify Questions
-
+### 2) Classify Questions
Rank and sort the questions based on interestingness and specificity.
-```python PYTHON
+
+```python
+# example labelled questions that act as a training samples for the classification
interestingness=[
- Example("What do you think is the hardest part of what I do for a living?", "Not Interesting"),
- Example("What\'s the first thing you noticed about me?", "Interesting"),
- Example("Do you think plants thrive or die in my care?", "Interesting"),
- Example("Do I seem like more of a creative or analytical type?", "Interesting"),
- Example("What subject do you think I thrived at in school?", "Not Interesting"),
- Example("What\'s been your happiest memory this past year?", "Interesting"),
- Example("What lesson took you the longest to un-learn?", "Not Interesting"),
- Example("How can you become a better person?", "Not Interesting"),
- Example("Do you think I intimidate others? Why or why not?", "Interesting"),
- Example("What\'s the most embarrassing thing that happened to you on a date?", "Not Interesting"),
- Example("How would you describe what you think my type is in three words?", "Interesting"),
- Example("What do you think I\'m most likely to splurge on?", "Interesting"),
- Example("As a child what do you think I wanted to be when I grow up?", "Interesting"),
- Example("Do you think you are usually early, on time, or late to events?", "Not Interesting"),
- Example("Do you think I was popular at school?", "Interesting"),
+ Example("What do you think is the hardest part of what I do for a living?", "Not Interesting"),
+ Example("What\'s the first thing you noticed about me?", "Interesting"),
+ Example("Do you think plants thrive or die in my care?", "Interesting"),
+ Example("Do I seem like more of a creative or analytical type?", "Interesting"),
+ Example("What subject do you think I thrived at in school?", "Not Interesting"),
+ Example("What\'s been your happiest memory this past year?", "Interesting"),
+ Example("What lesson took you the longest to un-learn?", "Not Interesting"),
+ Example("How can you become a better person?", "Not Interesting"),
+ Example("Do you think I intimidate others? Why or why not?", "Interesting"),
+ Example("What\'s the most embarrassing thing that happened to you on a date?", "Not Interesting"),
+ Example("How would you describe what you think my type is in three words?", "Interesting"),
+ Example("What do you think I\'m most likely to splurge on?", "Interesting"),
+ Example("As a child what do you think I wanted to be when I grow up?", "Interesting"),
+ Example("Do you think you are usually early, on time, or late to events?", "Not Interesting"),
+ Example("Do you think I was popular at school?", "Interesting"),
Example("What questions are you trying to answer most in your life right now?", "Not Interesting")]
specificity=[
- Example("What\'s the first thing you noticed about me?", "Specific"),
- Example("Do you think plants thrive or die in my care?", "Specific"),
- Example("Do I seem like more of a creative or analytical type?", "Not Specific"),
- Example("How would you describe what you think my type is in three words?", "Not Specific"),
- Example("What do you think I\'m most likely to splurge on?", "Specific"),
- Example("What subject do you think I thrived at in school?", "Not Specific"),
- Example("As a child what do you think I wanted to be when I grow up?", "Specific"),
- Example("Do you think I was popular at school?", "Specific"),
- Example("Do you think you\'re usually early, on time, or late to events?", "Specific"),
- Example("Do you think I intimidate others? Why or why not?", "Specific"),
- Example("What\'s been your happiest memory this past year?", "Not Specific"),
- Example("What subject do you think I thrived at in school?", "Specific"),
- Example("What\'s the biggest mistake that you think you needed to make to become who you are now?", "Specific"),
- Example("Is there anything you\'ve done recently that you\'re incredibly proud of?", "Not Specific"),
- Example("How are you and your siblings similar?", "Not Specific"),
- Example("What\'s the worst pain you have ever been in that wasn\'t physical?", "Specific"),
- Example("Has a stranger ever changed your life?", "Specific"),
- Example("Do you think the image you have of yourself matches the image other people see you as?", "Specific"),
+ Example("What\'s the first thing you noticed about me?", "Specific"),
+ Example("Do you think plants thrive or die in my care?", "Specific"),
+ Example("Do I seem like more of a creative or analytical type?", "Not Specific"),
+ Example("How would you describe what you think my type is in three words?", "Not Specific"),
+ Example("What do you think I\'m most likely to splurge on?", "Specific"),
+ Example("What subject do you think I thrived at in school?", "Not Specific"),
+ Example("As a child what do you think I wanted to be when I grow up?", "Specific"),
+ Example("Do you think I was popular at school?", "Specific"),
+ Example("Do you think you\'re usually early, on time, or late to events?", "Specific"),
+ Example("Do you think I intimidate others? Why or why not?", "Specific"),
+ Example("What\'s been your happiest memory this past year?", "Not Specific"),
+ Example("What subject do you think I thrived at in school?", "Specific"),
+ Example("What\'s the biggest mistake that you think you needed to make to become who you are now?", "Specific"),
+ Example("Is there anything you\'ve done recently that you\'re incredibly proud of?", "Not Specific"),
+ Example("How are you and your siblings similar?", "Not Specific"),
+ Example("What\'s the worst pain you have ever been in that wasn\'t physical?", "Specific"),
+ Example("Has a stranger ever changed your life?", "Specific"),
+ Example("Do you think the image you have of yourself matches the image other people see you as?", "Specific"),
Example("What would your younger self not believe about your life today?", "Specific")]
```
-```python PYTHON
+
+```python
def add_attribute(df, attribute, name, target):
response = co.classify(
@@ -126,7 +140,8 @@ def add_attribute(df, attribute, name, target):
df[name]=q_conf
```
-```python PYTHON
+
+```python
add_attribute(clean_q_df, interestingness, 'interestingness', 'Interesting')
add_attribute(clean_q_df, specificity, 'specificity', 'Specific')
clean_q_df['average']= clean_q_df.iloc[:,1:].mean(axis=1)
diff --git a/fern/pages/cookbooks/rag-evaluation-deep-dive.mdx b/fern/pages/cookbooks/rag-evaluation-deep-dive.mdx
index 3eee7a208..17e63df01 100644
--- a/fern/pages/cookbooks/rag-evaluation-deep-dive.mdx
+++ b/fern/pages/cookbooks/rag-evaluation-deep-dive.mdx
@@ -1,9 +1,9 @@
---
-title: Deep Dive Into Evaluating RAG Outputs
+title: Deep Dive Into RAG Evaluation
slug: /page/rag-evaluation-deep-dive
description: "This page contains information on evaluating the output of RAG systems."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG"
---
@@ -14,21 +14,23 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Marco Del Tredici",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/f103c96-Marco.jpg"
+ },
+ {
+ name: "Aal Patankar",
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d48e622-Aal.jpg"
+ }
]}
/>
-
-In this notebook, we'll show you how to evaluate the output of a RAG system. The high-level RAG flow is depicted in the diagram below.
+
-
-We will focus on the evaluation of **Retrieve** and **Response** (or **Generation**), and present a set of metrics for each phase. We will deep dive into each metric, to give you a full understanding of how we evaluate models and why we do it this way, and provide code so you can repdroduce on your own data.
+In this notebook, we'll show you how to evaluate the output of a RAG system. The high-level RAG flow is depicted in the diagram below.
+
+
+We will focus on the evaluation of **Retrive** and **Response** (or **Generation**), and present a set of metrics for each phase. We will deep dive into each metric, to give you a full understanding of how we evaluate models and why we do it this way, and provide code so you can repdroduce on your own data.
To demonstrate the metrics, we will use data from the [Docugami's KG-RAG](https://github.com/docugami/KG-RAG-datasets/tree/main/sec-10-q/data/v1) dataset, a RAG dataset for financial 10Q filing reports. We will focus only on evaluation, without performing the actual Retrieval and response Generation steps.
@@ -39,22 +41,28 @@ To demonstrate the metrics, we will use data from the [Docugami's KG-RAG](https:
3. [Generation Evaluation](#generation-evaluation)
4. [Final Comments](#final-comments)
-## Getting Started [#getting-started]
+
+## Getting Started
Let's start by setting the environment and downloading the dataset.
-```python PYTHON
+
+```python
%%capture
!pip install llama-index cohere openai
!pip install mistralai
```
-```python PYTHON
+
+```python
# required imports
+import cohere
from getpass import getpass
import os
import re
+import json
import numpy as np
+import pandas as pd
from llama_index.core import SimpleDirectoryReader
from llama_index.core.llama_dataset import download_llama_dataset, LabelledRagDataset
from openai import Client
@@ -64,7 +72,8 @@ from mistralai.client import MistralClient
For Response evaluation, we will use an LLM as a judge.
Any LLM can be used for this goal, but because evaluation is a very challenging task, we recommend using powerful LLMs, possibly as an ensemble of models. In [previous work](https://arxiv.org/pdf/2303.16634.pdf), it has been shown that models tend to assign higher scores to their own output. Since we generated the answers in this notebook using `command-r`, we will not use it for evaluation. We will provide two alternatives, `gpt-4` and `mistral`. We set `gpt-4` as the default model because, as mentioned above, evaluation is challenging, and `gpt-4` is powerful enough to efficiently perform the task.
-```python PYTHON
+
+```python
# Get keys
openai_api_key = getpass("Enter your OpenAI API Key: ")
# uncomment if you want to use mistral
@@ -77,14 +86,19 @@ model = "gpt-4"
```
-```python PYTHON
+ Enter your OpenAI API Key: ··········
+
+
+
+```python
if model == "gpt-4":
client = Client(api_key=openai_api_key)
else:
client = MistralClient(api_key=mistral_api_key)
```
-```python PYTHON
+
+```python
# let's define a function to get the model's response for a given input
def get_response(model, client, prompt):
response = client.chat.completions.create(
@@ -94,7 +108,8 @@ def get_response(model, client, prompt):
return response.choices[0].message.content
```
-```python PYTHON
+
+```python
# load the DocugamiKgRagSec10Q dataset
if os.path.exists("./data/source_files") and os.path.exists("./data/rag_dataset.json"):
rag_dataset = LabelledRagDataset.from_json("./data/rag_dataset.json")
@@ -103,19 +118,24 @@ else:
rag_dataset, documents = download_llama_dataset("DocugamiKgRagSec10Q", "./data")
```
-## Retrieval Evaluation [#retrieval-evaluation]
+ Loading files: 100%|██████████| 20/20 [01:44<00:00, 5.21s/file]
+
+
+
+## Retrieval Evaluation
In the Retrieval phase, we evaluate the set of **retrieved documents** against the **golden documents** set.
We use three standard metrics to evaluate retrieval:
-- **Precision**: the proportion of returned documents that are relevant, according to the gold annotation
-- **Recall**: the proportion of relevant documents in the gold data found in the retrieved documents
-- **Mean Average Precision** (**MAP**): measures the capability of the retriever to return relevant documents at the top of the list
+* **Precision**: the proportion of returned documents that are relevant, according to the gold annotation
+* **Recall**: the proportion of relevant documents in the gold data found in the retrieved documents
+* **Mean Average Precision** (**MAP**): measures the capability of the retriever to return relevant documents at the top of the list
We implement these three metrics in the class below:
-```python PYTHON
+
+```python
class RetrievalEvaluator:
def compute_precision(self, retrieved_documents, golden_documents):
@@ -140,14 +160,16 @@ class RetrievalEvaluator:
results = {'precision': [precision],
'recall': [recall],
'map': [map]}
- for k,v in results.items():
- print(f"{k}: {v[0]}")
+ results = pd.DataFrame(results)
+ return results
+
```
Let's now see how to use the class above to compute the results on a single datapoint.
-```python PYTHON
+
+```python
# select the index of a single datapoint - the first one in the dataset
idx = 0
@@ -165,13 +187,13 @@ print(f'Golden docs: {golden_docs}')
print(f'Retrieved docs: {retrieved_docs}')
```
-```txt title="Output"
-Query: How has Apple's total net sales changed over time?
-Golden docs: ['2022 Q3 AAPL.pdf', '2023 Q1 AAPL.pdf', '2023 Q2 AAPL.pdf', '2023 Q3 AAPL.pdf']
-Retrieved docs: ['2022 Q3 AAPL.pdf', '2023 Q1 MSFT.pdf', '2023 Q1 AAPL.pdf']
-```
+ Query: How has Apple's total net sales changed over time?
+ Golden docs: ['2022 Q3 AAPL.pdf', '2023 Q1 AAPL.pdf', '2023 Q2 AAPL.pdf', '2023 Q3 AAPL.pdf']
+ Retrieved docs: ['2022 Q3 AAPL.pdf', '2023 Q1 MSFT.pdf', '2023 Q1 AAPL.pdf']
+
+
-```python PYTHON
+```python
# we can now instantiate the evaluator
evaluate_retrieval = RetrievalEvaluator()
@@ -180,32 +202,127 @@ evaluate_retrieval.run_evals(retrieved_docs,golden_docs)
```
-```txt title="Output"
-precision: 0.67
-recall: 0.5
-map: 0.83
-```
+
+
+
+
+
+
+
+
+
+
+ |
+ precision |
+ recall |
+ map |
+
+
+
+
+ 0 |
+ 0.67 |
+ 0.5 |
+ 0.83 |
+
+
+
+
+
+
+
+
+
What are the figures above telling us?
-- Precision (0.67) tells us that 2 out of 3 of the retrieved docs are correct
-- Recall (0.5) means that 2 out of 4 relevant docs have been retrieved
-- MAP (0.83) is computed as the average of 1/1 (the highest ranked doc is correct) and 2/3 (the 2nd ranked doc is wrong, the 3rd is correct).
+* Precision (0.67) tells us that 2 out of 3 of the retrieved docs are correct
+* Recall (0.5) means that 2 out of 4 relevant docs have been retrieved
+* MAP (0.83) is computed as the average of 1/1 (the highest ranked doc is correct) and 2/3 (the 2nd ranked doc is wrong, the 3rd is correct).
While the example here focuses on a single datapoint, you can easily apply the same metrics to all your dataset and get the overall performance of your Retrieve phase.
-## Generation Evaluation [#generation-evaluation]
+
+## Generation Evaluation
Evaluating grounded generation (the second step of RAG) is notoriously difficult, because generations are usually complex and rich of information, and simply labelling an answer as "good" or "bad" is not enough.
-To overcome this issue, we first decompose complex answers into a set of basic _claims_, where a claim is any sentence or part of a sentence in the answer that expresses a verifiable fact. Subsequently, we check the validity of each claim independently, defining the overall quality of the answer based on the correctness of the claims it includes.
+To overcome this issue, we first decompose complex answers into a set of basic *claims*, where a claim is any sentence or part of a sentence in the answer that expresses a verifiable fact. Subsequently, we check the validity of each claim independently, defining the overall quality of the answer based on the correctness of the claims it includes.
We use claims to compute three metrics:
-- **Faithfulness**, which measures how many of the claims in the generated response are supported by the retrieved documents. This is a fundamental metric, as it tells us how _grounded_ in the documents the response is, and, contextually, it allows us to spot hallucinations
+* **Faithfulness**, which measures how many of the claims in the generated response are supported by the retrieved documents. This is a fundamental metric, as it tells us how *grounded* in the documents the response is, and, contextually, it allows us to spot hallucinations
-- **Correctness**, which checks which claims in the response also occur in the gold answer
+* **Correctness**, which checks which claims in the response also occur in the gold answer
-- And **Coverage**, by which we assess how many of the claims in the gold answer are included in the generated response.
+* And **Coverage**, by which we assess how many of the claims in the gold answer are included in the generated response.
Note that Faithfulness and Correctness share the exact same approach, the difference being that the former checks the claims against the supporting docs, while the latter against the golden answer.
Also, while Correctness is measuring the precision of the claims in the response, Coverage can be seen as complementary, as it measures recall.
@@ -214,7 +331,8 @@ Also, while Correctness is measuring the precision of the claims in the response
Let's now see how we implement the evaluation described above using LLMs. Let's start with **claim extraction**.
-```python PYTHON
+
+```python
# first, let's define a function which extracts the claims from a response
def extract_claims(query, response, model, client):
@@ -231,7 +349,8 @@ def extract_claims(query, response, model, client):
```
-```python PYTHON
+
+```python
# now, let's consider this answer, which we previously generated with command-r
response = "Apple's total net sales experienced a decline over the last year. The three-month period ended July 1, 2023, saw a total net sale of $81,797 million, which was a 1% decrease from the same period in 2022. The nine-month period ended July 1, 2023, fared slightly better, with a 3% decrease in net sales compared to the first nine months of 2022.\nThis downward trend continued into the three and six-month periods ending April 1, 2023. Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022."
@@ -242,22 +361,22 @@ claims = extract_claims(query, response, model, client)
print(f"List of claims extracted from the model's response:\n\n{claims}")
```
-```txt title="Output"
-List of claims extracted from the model's response:
+ List of claims extracted from the model's response:
+
+ - Apple's total net sales experienced a decline over the last year.
+ - The three-month period ended July 1, 2023, saw a total net sale of $81,797 million.
+ - This was a 1% decrease from the same period in 2022.
+ - The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022.
+ - The downward trend continued into the three and six-month periods ending April 1, 2023.
+ - Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022.
-- Apple's total net sales experienced a decline over the last year.
-- The three-month period ended July 1, 2023, saw a total net sale of $81,797 million.
-- This was a 1% decrease from the same period in 2022.
-- The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022.
-- The downward trend continued into the three and six-month periods ending April 1, 2023.
-- Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022.
-```
### Claim Assessment
Nice! now that we have the list of claims, we can go ahead and **assess the validity** of each claim.
-```python PYTHON
+
+```python
# Let's create a function that checks each claim against a reference text,
# which here we will call "context". As you will see, we will use different contexts,
# depending on the metric we want to compute.
@@ -282,7 +401,8 @@ def assess_claims(query, claims, context, model, client):
### Faithfulness
-```python PYTHON
+
+```python
# Let's start with Faithfulness: in this case, we want to assess the claims
# in the response against the retrieved documents (i.e., context = retrieved documents)
@@ -299,20 +419,20 @@ assessed_claims_faithfulness = assess_claims(query=query,
print(f"Assessment of the claims extracted from the model's response:\n\n{assessed_claims_faithfulness}")
```
-```txt title="Output"
-Assessment of the claims extracted from the model's response:
+ Assessment of the claims extracted from the model's response:
+
+ - Apple's total net sales experienced a decline over the last year. SUPPORTED=1
+ - The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
+ - This was a 1% decrease from the same period in 2022. SUPPORTED=1
+ - The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022. SUPPORTED=1
+ - The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
+ - Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022. SUPPORTED=1
-- Apple's total net sales experienced a decline over the last year. SUPPORTED=1
-- The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
-- This was a 1% decrease from the same period in 2022. SUPPORTED=1
-- The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022. SUPPORTED=1
-- The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
-- Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022. SUPPORTED=1
-```
Great, we now have an assessment for each of the claims: in the last step, we just need to use these assessments to define the final score.
-```python PYTHON
+
+```python
# given the list of claims and their label, compute the final score
# as the proportion of correct claims over the full list of claims
def get_final_score(claims_list):
@@ -322,20 +442,21 @@ def get_final_score(claims_list):
return round(score, 2)
```
-```python PYTHON
+
+```python
score_faithfulness = get_final_score(assessed_claims_faithfulness)
print(f'Faithfulness: {score_faithfulness}')
```
-```txt title="Output"
-Faithfulness: 1.0
-```
+ Faithfulness: 1.0
+
The final Faithfulness score is 1, which means that the model's response is fully grounded in the retrieved documents: that's a very good news :)
Before moving on, let's modify the model's response by adding a piece of information which is **not** grounded in any document, and re-compute Faithfulness.
-```python PYTHON
+
+```python
# let's mess up the century, changing 2022 to 1922
modified_response = response.replace('2022', '1922')
@@ -355,18 +476,17 @@ score_faithfulness_modified_claims = get_final_score(assessed_modified_claims)
print(f'Faithfulness: {score_faithfulness_modified_claims}')
```
-```txt title="Output"
-Assessment of the modified claims:
-
-- Apple's total net sales experienced a decline over the last year. SUPPORTED=1
-- The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
-- This was a 1% decrease from the same period in 1922. SUPPORTED=0
-- The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 1922. SUPPORTED=0
-- The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
-- Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 1922. SUPPORTED=0
+ Assessment of the modified claims:
+
+ - Apple's total net sales experienced a decline over the last year. SUPPORTED=1
+ - The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
+ - This was a 1% decrease from the same period in 1922. SUPPORTED=0
+ - The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 1922. SUPPORTED=0
+ - The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
+ - Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 1922. SUPPORTED=0
+
+ Faithfulness: 0.5
-Faithfulness: 0.5
-```
As you can see, by assessing claims one by one, we are able to spot **hallucinations**, that is, the (corrupted) cases in which the information provided by the model is not grounded in any of the retrieved documents.
@@ -374,7 +494,8 @@ As you can see, by assessing claims one by one, we are able to spot **hallucinat
As said, Faithfulness and Correctness share the same logic, the only difference being that we will check the claims against the gold answer. We can therefore repeat the process above, and just substitute the `context`.
-```python PYTHON
+
+```python
# let's get the gold answer from the dataset
golden_answer = rag_dataset[idx].reference_answer
@@ -391,56 +512,57 @@ assessed_claims_correctness = assess_claims(query=query,
print(f"Assess the claims extracted from the model's response against the golden answer:\n\n{assessed_claims_correctness}")
```
-```txt title="Output"
-Assess the claims extracted from the model's response against the golden answer:
+ Assess the claims extracted from the model's response against the golden answer:
+
+ - Apple's total net sales experienced a decline over the last year. SUPPORTED=1
+ - The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
+ - This was a 1% decrease from the same period in 2022. SUPPORTED=0
+ - The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022. SUPPORTED=0
+ - The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
+ - Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022. SUPPORTED=0
-- Apple's total net sales experienced a decline over the last year. SUPPORTED=1
-- The three-month period ended July 1, 2023, saw a total net sale of $81,797 million. SUPPORTED=1
-- This was a 1% decrease from the same period in 2022. SUPPORTED=0
-- The nine-month period ended July 1, 2023, had a 3% decrease in net sales compared to the first nine months of 2022. SUPPORTED=0
-- The downward trend continued into the three and six-month periods ending April 1, 2023. SUPPORTED=1
-- Apple's total net sales decreased by 3% and 4% respectively, compared to the same periods in 2022. SUPPORTED=0
-```
As mentioned above, automatic evaluation is a hard task, and even when using powerful models, claim assessment can present problems: for example, the third claim is labelled as 0, even if it might be inferred from the information in the gold answer.
-```python PYTHON
+
+```python
# we can now compute the final Correctness score
score_correctness = get_final_score(assessed_claims_correctness)
print(f'Correctness: {score_correctness}')
```
-```txt title="Output"
-Correctness: 0.5
-```
+ Correctness: 0.5
+
+
+For Correctness, we found that only half of the claims in the generated response are found in the gold answer. Note that this is not necessarily an issue: reference answers are often non-exhaustive, especially in dataset including open-ended questions, like the one we are considering in this post, and *both* the generated and golden answer can include relevant information.
-For Correctness, we found that only half of the claims in the generated response are found in the gold answer. Note that this is not necessarily an issue: reference answers are often non-exhaustive, especially in dataset including open-ended questions, like the one we are considering in this post, and _both_ the generated and golden answer can include relevant information.
### Coverage
-We finally move to Coverage. Remember that, in this case, we want to check how many of the claims _in the gold answer_ are included in the generated response. To do it, we first need to extract the claims from the gold answer.
+We finally move to Coverage. Remember that, in this case, we want to check how many of the claims *in the gold answer* are included in the generated response. To do it, we first need to extract the claims from the gold answer.
+
-```python PYTHON
+```python
# let's extract the golden claims
gold_claims = extract_claims(query, golden_answer, model, client)
print(f"List of claims extracted from the gold answer:\n\n{gold_claims}")
```
-```txt title="Output"
-List of claims extracted from the gold answer:
+ List of claims extracted from the gold answer:
+
+ - For the quarterly period ended June 25, 2022, the total net sales were $82,959 million.
+ - For the quarterly period ended December 31, 2022, the total net sales were $117,154 million.
+ - For the quarterly period ended April 1, 2023, the total net sales were $94,836 million.
+ - For the quarterly period ended July 1, 2023, the total net sales were $81,797 million.
+ - There was an increase in total net sales from the quarter ended June 25, 2022, to the quarter ended December 31, 2022.
+ - There was a decrease in total net sales in the quarters ended April 1, 2023, and July 1, 2023.
-- For the quarterly period ended June 25, 2022, the total net sales were $82,959 million.
-- For the quarterly period ended December 31, 2022, the total net sales were $117,154 million.
-- For the quarterly period ended April 1, 2023, the total net sales were $94,836 million.
-- For the quarterly period ended July 1, 2023, the total net sales were $81,797 million.
-- There was an increase in total net sales from the quarter ended June 25, 2022, to the quarter ended December 31, 2022.
-- There was a decrease in total net sales in the quarters ended April 1, 2023, and July 1, 2023.
-```
Then, we check which of these claims is present in the response generated by the model.
-```python PYTHON
+
+```python
# note that in, this case, the context is the model's response
assessed_claims_coverage = assess_claims(query=query,
claims=gold_claims,
@@ -452,31 +574,31 @@ assessed_claims_coverage = assess_claims(query=query,
print(f"Assess which of the gold claims is in the model's response:\n\n{assessed_claims_coverage}")
```
-```txt title="Output"
-Assess which of the gold claims is in the model's response:
+ Assess which of the gold claims is in the model's response:
+
+ - For the quarterly period ended June 25, 2022, the total net sales were $82,959 million. SUPPORTED=0
+ - For the quarterly period ended December 31, 2022, the total net sales were $117,154 million. SUPPORTED=0
+ - For the quarterly period ended April 1, 2023, the total net sales were $94,836 million. SUPPORTED=0
+ - For the quarterly period ended July 1, 2023, the total net sales were $81,797 million. SUPPORTED=1
+ - There was an increase in total net sales from the quarter ended June 25, 2022, to the quarter ended December 31, 2022. SUPPORTED=0
+ - There was a decrease in total net sales in the quarters ended April 1, 2023, and July 1, 2023. SUPPORTED=1
-- For the quarterly period ended June 25, 2022, the total net sales were $82,959 million. SUPPORTED=0
-- For the quarterly period ended December 31, 2022, the total net sales were $117,154 million. SUPPORTED=0
-- For the quarterly period ended April 1, 2023, the total net sales were $94,836 million. SUPPORTED=0
-- For the quarterly period ended July 1, 2023, the total net sales were $81,797 million. SUPPORTED=1
-- There was an increase in total net sales from the quarter ended June 25, 2022, to the quarter ended December 31, 2022. SUPPORTED=0
-- There was a decrease in total net sales in the quarters ended April 1, 2023, and July 1, 2023. SUPPORTED=1
-```
-```python PYTHON
+
+```python
# we compute the final Coverage score
score_coverage = get_final_score(assessed_claims_coverage)
print(f'Coverage: {score_coverage}')
```
-```txt title="Output"
-Coverage: 0.33
-```
+ Coverage: 0.33
+
The Coverage score is telling us that 1/3 of the information in the gold answer is present in the generated answer. This is a useful information, that, similarly to what said above regarding Correctness, can raise further questions, such as: is it acceptable to have diverging information in the generated answer? Is any crucial piece of information missing in the generated answer?
The answer to these questions is use case-specific, and has to be made by the end user: The claim-based approach implemented here supports the user by providing a clear and detailed view on what the model is assessing and how.
-## Final Comments [#final-comments]
+
+## Final Comments
RAG evaluation is a hard task, especially the evaluation of the generated response. In this notebook we offer a clear, robust and replicable approach to evaluation, on which you can build on to build your evaluation pipeline.
diff --git a/fern/pages/cookbooks/rag-with-chat-embed.mdx b/fern/pages/cookbooks/rag-with-chat-embed.mdx
index 20cedc9e5..6ccc53ca1 100644
--- a/fern/pages/cookbooks/rag-with-chat-embed.mdx
+++ b/fern/pages/cookbooks/rag-with-chat-embed.mdx
@@ -3,16 +3,23 @@ title: RAG With Chat Embed and Rerank via Pinecone
slug: /page/rag-with-chat-embed
description: "This page contains a basic tutorial on how to build a RAG-powered chatbot."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, retrieval-augmented generation, RAG, chatbot"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-This notebook shows how to build a RAG-powered chatbot with Cohere's Chat endpoint. The chatbot can extract relevant information from external documents and produce verifiable, inline citations in its responses.
+
+
+
+
+
+
+
+
+This notebook shows how to build a RAG-powered chatbot with Cohere's Chat endpoint. The chatbot can extract relevant information from external documents and produce verifiable, inline citations in its responses.
This application will use several Cohere API endpoints:
@@ -22,19 +29,14 @@ This application will use several Cohere API endpoints:
The diagram below provides an overview of what we’ll build.
-
+
Here is a summary of the steps involved.
Initial phase:
-
- **Step 0**: Ingest the documents – get documents, chunk, embed, and index.
For each user-chatbot interaction:
-
- **Step 1**: Get the user message
- **Step 2**: Call the Chat endpoint in query-generation mode
- If at least one query is generated
@@ -43,11 +45,15 @@ For each user-chatbot interaction:
- If no query is generated
- **Step 4**: Call the Chat endpoint in normal mode to generate a response
-```python PYTHON
+# Setup
+
+
+```python
! pip install cohere hnswlib unstructured python-dotenv -q
```
-```python PYTHON
+
+```python
import cohere
from pinecone import Pinecone, PodSpec
import uuid
@@ -60,7 +66,8 @@ co = cohere.Client("COHERE_API_KEY") # Get your API key here: https://dashboard.
pc = Pinecone(api_key="PINECONE_API_KEY") # (get API key at app.pinecone.io)
```
-```python PYTHON
+
+```python
import cohere
import os
import dotenv
@@ -73,9 +80,30 @@ pc = Pinecone(
```
-First, we define the list of documents we want to ingest and make available for retrieval. As an example, we'll use the contents from the first module of Cohere's _LLM University: What are Large Language Models?_.
-```python PYTHON
+```python
+# #@title Enable text wrapping in Google Colab
+# Uncomment the code below for Google Colab
+
+# from IPython.display import HTML, display
+
+# def set_css():
+# display(HTML('''
+#
+# '''))
+# get_ipython().events.register('pre_run_cell', set_css)
+```
+
+# Create a vector store for ingestion and retrieval
+
+First, we define the list of documents we want to ingest and make available for retrieval. As an example, we'll use the contents from the first module of Cohere's *LLM University: What are Large Language Models?*.
+
+
+```python
raw_documents = [
{
"title": "Text Embeddings",
@@ -92,24 +120,26 @@ raw_documents = [
]
```
-Usually the number of documents for practical applications is vast, and so we'll need to be able to search documents efficiently. This involves breaking the documents into chunks, generating embeddings, and indexing the embeddings, as shown in the image below.
+Usually the number of documents for practical applications is vast, and so we'll need to be able to search documents efficiently. This involves breaking the documents into chunks, generating embeddings, and indexing the embeddings, as shown in the image below.
-We implement this in the `Vectorstore` class below, which takes the `raw_documents` list as input. Three methods are immediately called when creating an object of the `Vectorstore` class:
+We implement this in the `Vectorstore` class below, which takes the `raw_documents` list as input. Three methods are immediately called when creating an object of the `Vectorstore` class:
-`load_and_chunk()`
-This method uses the `partition_html()` method from the `unstructured` library to load the documents from URL and break them into smaller chunks. Each chunk is turned into a dictionary object with three fields:
+`load_and_chunk()`
+This method uses the `partition_html()` method from the `unstructured` library to load the documents from URL and break them into smaller chunks. Each chunk is turned into a dictionary object with three fields:
- `title` - the web page’s title,
- `text` - the textual content of the chunk, and
-- `url` - the web page’s URL.
-
+- `url` - the web page’s URL.
+
+
`embed()`
-This method uses Cohere's `embed-english-v3.0` model to generate embeddings of the chunked documents. Since our documents will be used for retrieval, we set `input_type="search_document"`. We send the documents to the Embed endpoint in batches, because the endpoint has a limit of 96 documents per call.
+This method uses Cohere's `embed-english-v3.0` model to generate embeddings of the chunked documents. Since our documents will be used for retrieval, we set `input_type="search_document"`. We send the documents to the Embed endpoint in batches, because the endpoint has a limit of 96 documents per call.
`index()`
-This method uses the `hsnwlib` package to index the document chunk embeddings. This will ensure efficient similarity search during retrieval. Note that `hnswlib` uses a vector library, and we have chosen it for its simplicity.
+This method uses the `hsnwlib` package to index the document chunk embeddings. This will ensure efficient similarity search during retrieval. Note that `hnswlib` uses a vector library, and we have chosen it for its simplicity.
+
-```python PYTHON
+```python
class Vectorstore:
"""
A class representing a collection of documents indexed into a vectorstore.
@@ -194,10 +224,10 @@ class Vectorstore:
environment="gcp-starter"
)
)
-
+
# connect to index
self.idx = pc.Index(index_name)
-
+
batch_size = 128
ids = [str(i) for i in range(len(self.docs))]
@@ -241,9 +271,9 @@ class Vectorstore:
top_n=self.rerank_top_k,
model="rerank-english-v2.0",
)
-
+
docs_reranked = [res['matches'][result.index] for result in rerank_results.results]
-
+
for doc in docs_reranked:
docs_retrieved.append(doc['metadata'])
@@ -252,18 +282,19 @@ class Vectorstore:
In the code cell below, we initialize an instance of the `Vectorstore` class and pass in the `raw_documents` list as input.
-```python PYTHON
+
+```python
+# Create an instance of the Vectorstore class with the given sources
vectorstore = Vectorstore(raw_documents)
```
-```
-Loading documents...
-Embedding document chunks...
-Indexing documents...
-Indexing complete
-```
+ Loading documents...
+ Embedding document chunks...
+ Indexing documents...
+ Indexing complete
-The `Vectorstore` class also has a `retrieve()` method, which we'll use to retrieve relevant document chunks given a query (as in Step 3 in the diagram shared at the beginning of this notebook). This method has two components: (1) dense retrieval, and (2) reranking.
+
+The `Vectorstore` class also has a `retrieve()` method, which we'll use to retrieve relevant document chunks given a query (as in Step 3 in the diagram shared at the beginning of this notebook). This method has two components: (1) dense retrieval, and (2) reranking.
### Dense retrieval
@@ -273,9 +304,9 @@ Search is performed by the `knn_query()` method from the `hnswlib` library. Give
### Reranking
-After semantic search, we implement a reranking step. While our semantic search component is already highly capable of retrieving relevant sources, the [Rerank endpoint](https://cohere.com/rerank) provides an additional boost to the quality of the search results, especially for complex and domain-specific queries. It takes the search results and sorts them according to their relevance to the query.
+After semantic search, we implement a reranking step. While our semantic search component is already highly capable of retrieving relevant sources, the [Rerank endpoint](https://cohere.com/rerank) provides an additional boost to the quality of the search results, especially for complex and domain-specific queries. It takes the search results and sorts them according to their relevance to the query.
-We call the Rerank endpoint with the `co.rerank()` method and define the number of top reranked document chunks to retrieve using the attribute `self.rerank_top_k=3`. The model we use is `rerank-english-v2.0`.
+We call the Rerank endpoint with the `co.rerank()` method and define the number of top reranked document chunks to retrieve using the attribute `self.rerank_top_k=3`. The model we use is `rerank-english-v2.0`.
This method returns the top retrieved document chunks `chunks_retrieved` so that they can be passed to the chatbot.
@@ -283,38 +314,44 @@ In the code cell below, we check the document chunks that are retrieved for the
## Test Retrieval
-```python PYTHON
+
+```python
vectorstore.retrieve("multi-head attention definition")
```
-```
-[{'text': 'The attention step used in transformer models is actually much more powerful, and it’s called multi-head attention. In multi-head attention, several different embeddings are used to modify the vectors and add context to them. Multi-head attention has helped language models reach much higher levels of efficacy when processing and generating text.',
- 'title': 'Transformer Models',
- 'url': 'https://docs.cohere.com/docs/transformer-models'},
- {'text': "What you learned in this chapter is simple self-attention. However, we can do much better than that. There is a method called multi-head attention, in which one doesn't only consider one embedding, but several different ones. These are all obtained from the original by transforming it in different ways. Multi-head attention has been very successful at the task of adding context to text. If you'd like to learn more about the self and multi-head attention, you can check out the following two",
- 'title': 'The Attention Mechanism',
- 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'},
- {'text': 'Attention helps give context to each word, based on the other words in the sentence (or text).',
- 'title': 'Transformer Models',
- 'url': 'https://docs.cohere.com/docs/transformer-models'}]
-```
-Next, we implement a class to handle the interaction between the user and the chatbot. It takes an instance of the `Vectorstore` class as input.
-The `run()` method will be used to run the chatbot application. It begins with the logic for getting the user message, along with a way for the user to end the conversation.
-Based on the user message, the chatbot needs to decide if it needs to consult external information before responding. If so, the chatbot determines an optimal set of search queries to use for retrieval. When we call `co.chat()` with `search_queries_only=True`, the Chat endpoint handles this for us automatically.
+ [{'text': 'The attention step used in transformer models is actually much more powerful, and it’s called multi-head attention. In multi-head attention, several different embeddings are used to modify the vectors and add context to them. Multi-head attention has helped language models reach much higher levels of efficacy when processing and generating text.',
+ 'title': 'Transformer Models',
+ 'url': 'https://docs.cohere.com/docs/transformer-models'},
+ {'text': "What you learned in this chapter is simple self-attention. However, we can do much better than that. There is a method called multi-head attention, in which one doesn't only consider one embedding, but several different ones. These are all obtained from the original by transforming it in different ways. Multi-head attention has been very successful at the task of adding context to text. If you'd like to learn more about the self and multi-head attention, you can check out the following two",
+ 'title': 'The Attention Mechanism',
+ 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'},
+ {'text': 'Attention helps give context to each word, based on the other words in the sentence (or text).',
+ 'title': 'Transformer Models',
+ 'url': 'https://docs.cohere.com/docs/transformer-models'}]
+
+
+
+# Create a chatbot
-The generated queries can be accessed from the `search_queries` field of the object that is returned. Then, what happens next depends on how many queries are returned.
+Next, we implement a class to handle the interaction between the user and the chatbot. It takes an instance of the `Vectorstore` class as input.
-- If queries are returned, we call the `retrieve()` method of the Vectorstore object for the retrieval step. The retrieved document chunks are then passed to the Chat endpoint by adding a `documents` parameter when we call `co.chat()` again.
+The `run()` method will be used to run the chatbot application. It begins with the logic for getting the user message, along with a way for the user to end the conversation.
+
+Based on the user message, the chatbot needs to decide if it needs to consult external information before responding. If so, the chatbot determines an optimal set of search queries to use for retrieval. When we call `co.chat()` with `search_queries_only=True`, the Chat endpoint handles this for us automatically.
+
+The generated queries can be accessed from the `search_queries` field of the object that is returned. Then, what happens next depends on how many queries are returned.
+- If queries are returned, we call the `retrieve()` method of the Vectorstore object for the retrieval step. The retrieved document chunks are then passed to the Chat endpoint by adding a `documents` parameter when we call `co.chat()` again.
- Otherwise, if no queries are returned, we call the Chat endpoint another time, passing the user message and without needing to add any documents to the call.
In either case, we also pass the `conversation_id` parameter, which retains the interactions between the user and the chatbot in the same conversation thread. We also enable the `stream` parameter so we can stream the chatbot response.
-We then print the chatbot's response. In the case that the external information was used to generate a response, we also display citations.
+We then print the chatbot's response. In the case that the external information was used to generate a response, we also display citations.
-```python PYTHON
+
+```python
class Chatbot:
def __init__(self, vectorstore: Vectorstore):
"""
@@ -400,74 +437,123 @@ class Chatbot:
print(f"\n{'-'*100}\n")
```
-We can now run the chatbot. For this, we create the instance of `Chatbot` and run the chatbot by invoking the `run()` method.
-The format of each citation is:
+
+
+
+
+
+
+
+
+
+
+# Run the chatbot
+
+We can now run the chatbot. For this, we create the instance of `Chatbot` and run the chatbot by invoking the `run()` method.
+
+The format of each citation is:
- `start`: The starting point of a span where one or more documents are referenced
- `end`: The ending point of a span where one or more documents are referenced
- `text`: The text representing this span
- `document_ids`: The IDs of the documents being referenced (`doc_0` being the ID of the first document passed to the `documents` creating parameter in the endpoint call, and so on)
-```python PYTHON
+
+```python
+# Create an instance of the Chatbot class
chatbot = Chatbot(vectorstore)
+# Run the chatbot
chatbot.run()
```
-```
-Chatbot:
-Hello! What's your question? I'm here to help you in any way I can.
-----------------------------------------------------------------------------------------------------
-
-Retrieving information...
-Chatbot:
-Word embeddings associate words with lists of numbers, so that similar words are close to each other and dissimilar words are further away.
-Sentence embeddings do the same thing, but for sentences. Each sentence is associated with a vector of numbers in a coherent way, so that similar sentences are assigned similar vectors, and different sentences are given different vectors.
-
-CITATIONS:
-start=0 end=15 text='Word embeddings' document_ids=['doc_0']
-start=16 end=53 text='associate words with lists of numbers' document_ids=['doc_0']
-start=63 end=100 text='similar words are close to each other' document_ids=['doc_0']
-start=105 end=139 text='dissimilar words are further away.' document_ids=['doc_0']
-start=140 end=159 text='Sentence embeddings' document_ids=['doc_0', 'doc_2']
-start=160 end=177 text='do the same thing' document_ids=['doc_0', 'doc_2']
-start=198 end=211 text='Each sentence' document_ids=['doc_0', 'doc_2']
-start=215 end=250 text='associated with a vector of numbers' document_ids=['doc_0', 'doc_2']
-start=256 end=264 text='coherent' document_ids=['doc_2']
-start=278 end=295 text='similar sentences' document_ids=['doc_0', 'doc_2']
-start=300 end=324 text='assigned similar vectors' document_ids=['doc_0', 'doc_2']
-start=330 end=349 text='different sentences' document_ids=['doc_0', 'doc_2']
-start=354 end=378 text='given different vectors.' document_ids=['doc_0', 'doc_2']
-
-DOCUMENTS:
-{'id': 'doc_0', 'text': 'In the previous chapters, you learned about word and sentence embeddings and similarity between words and sentences. In short, a word embedding is a way to associate words with lists of numbers (vectors) in such a way that similar words are associated with numbers that are close by, and dissimilar words with numbers that are far away from each other. A sentence embedding does the same thing, but associating a vector to every sentence. Similarity is a way to measure how similar two words (or', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
-{'id': 'doc_1', 'text': 'Sentence embeddings\n\nSo word embeddings seem to be pretty useful, but in reality, human language is much more complicated than simply a bunch of words put together. Human language has structure, sentences, etc. How would one be able to represent, for instance, a sentence? Well, here’s an idea. How about the sums of scores of all the words? For example, say we have a word embedding that assigns the following scores to these words:\n\nNo: [1,0,0,0]\n\nI: [0,2,0,0]\n\nAm: [-1,0,1,0]\n\nGood: [0,0,1,3]', 'title': 'Text Embeddings', 'url': 'https://docs.cohere.com/docs/text-embeddings'}
-{'id': 'doc_2', 'text': 'This is where sentence embeddings come into play. A sentence embedding is just like a word embedding, except it associates every sentence with a vector full of numbers, in a coherent way. By coherent, I mean that it satisfies similar properties as a word embedding. For instance, similar sentences are assigned to similar vectors, different sentences are assigned to different vectors, and most importantly, each of the coordinates of the vector identifies some (whether clear or obscure) property of', 'title': 'Text Embeddings', 'url': 'https://docs.cohere.com/docs/text-embeddings'}
-
-----------------------------------------------------------------------------------------------------
-
-Retrieving information...
-Chatbot:
-The similarities between words and sentences are both quantitative measures of how close the two given items are. There are two types of similarities that can be defined: dot product similarity, and cosine similarity. These methods can determine how similar two words, or sentences, are.
-
-CITATIONS:
-start=54 end=75 text='quantitative measures' document_ids=['doc_0']
-start=79 end=88 text='how close' document_ids=['doc_0']
-start=124 end=133 text='two types' document_ids=['doc_0', 'doc_4']
-start=171 end=193 text='dot product similarity' document_ids=['doc_0', 'doc_4']
-start=199 end=217 text='cosine similarity.' document_ids=['doc_0', 'doc_4']
-start=236 end=257 text='determine how similar' document_ids=['doc_0', 'doc_4']
-
-DOCUMENTS:
-{'id': 'doc_0', 'text': 'Now that we know embeddings quite well, let’s move on to using them to find similarities. There are two types of similarities we’ll define in this post: dot product similarity and cosine similarity. Both are very similar and very useful to determine if two words (or sentences) are similar.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
-{'id': 'doc_1', 'text': 'But let me add some numbers to this reasoning to make it more clear. Imagine that we calculate similarities for the words in each sentence, and we get the following:\n\nThis similarity makes sense in the following ways:\n\nThe similarity between each word and itself is 1.\n\nThe similarity between any irrelevant word (“the”, “of”, etc.) and any other word is 0.\n\nThe similarity between “bank” and “river” is 0.11.\n\nThe similarity between “bank” and “money” is 0.25.', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
-{'id': 'doc_2', 'text': 'And the results are:\n\nThe similarity between sentences 1 and 2: 6738.2858668486715\n\nThe similarity between sentences 1 and 3: -122.22666955510499\n\nThe similarity between sentences 2 and 3: -3.494608113647928\n\nThese results certainly confirm our predictions. The similarity between sentences 1 and 2 is 6738, which is high. The similarities between sentences 1 and 3, and 2 and 3, are -122 and -3.5 (dot products are allowed to be negative too!), which are much lower.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
-{'id': 'doc_3', 'text': 'But let me add some numbers to this reasoning to make it more clear. Imagine that we calculate similarities for the words in each sentence, and we get the following:\n\nThis similarity makes sense in the following ways:\n\nThe similarity between each word and itself is 1.\n\nThe similarity between any irrelevant word (“the”, “of”, etc.) and any other word is 0.\n\nThe similarity between “bank” and “river” is 0.11.\n\nThe similarity between “bank” and “money” is 0.25.', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
-{'id': 'doc_4', 'text': 'Now that we know embeddings quite well, let’s move on to using them to find similarities. There are two types of similarities we’ll define in this post: dot product similarity and cosine similarity. Both are very similar and very useful to determine if two words (or sentences) are similar.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
-{'id': 'doc_5', 'text': 'And the results are:\n\nThe similarity between sentences 1 and 2: 6738.2858668486715\n\nThe similarity between sentences 1 and 3: -122.22666955510499\n\nThe similarity between sentences 2 and 3: -3.494608113647928\n\nThese results certainly confirm our predictions. The similarity between sentences 1 and 2 is 6738, which is high. The similarities between sentences 1 and 3, and 2 and 3, are -122 and -3.5 (dot products are allowed to be negative too!), which are much lower.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
-
-----------------------------------------------------------------------------------------------------
-
-Ending chat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Chatbot:
+ Hello! What's your question? I'm here to help you in any way I can.
+ ----------------------------------------------------------------------------------------------------
+
+ Retrieving information...
+ Chatbot:
+ Word embeddings associate words with lists of numbers, so that similar words are close to each other and dissimilar words are further away.
+ Sentence embeddings do the same thing, but for sentences. Each sentence is associated with a vector of numbers in a coherent way, so that similar sentences are assigned similar vectors, and different sentences are given different vectors.
+
+ CITATIONS:
+ start=0 end=15 text='Word embeddings' document_ids=['doc_0']
+ start=16 end=53 text='associate words with lists of numbers' document_ids=['doc_0']
+ start=63 end=100 text='similar words are close to each other' document_ids=['doc_0']
+ start=105 end=139 text='dissimilar words are further away.' document_ids=['doc_0']
+ start=140 end=159 text='Sentence embeddings' document_ids=['doc_0', 'doc_2']
+ start=160 end=177 text='do the same thing' document_ids=['doc_0', 'doc_2']
+ start=198 end=211 text='Each sentence' document_ids=['doc_0', 'doc_2']
+ start=215 end=250 text='associated with a vector of numbers' document_ids=['doc_0', 'doc_2']
+ start=256 end=264 text='coherent' document_ids=['doc_2']
+ start=278 end=295 text='similar sentences' document_ids=['doc_0', 'doc_2']
+ start=300 end=324 text='assigned similar vectors' document_ids=['doc_0', 'doc_2']
+ start=330 end=349 text='different sentences' document_ids=['doc_0', 'doc_2']
+ start=354 end=378 text='given different vectors.' document_ids=['doc_0', 'doc_2']
+
+ DOCUMENTS:
+ {'id': 'doc_0', 'text': 'In the previous chapters, you learned about word and sentence embeddings and similarity between words and sentences. In short, a word embedding is a way to associate words with lists of numbers (vectors) in such a way that similar words are associated with numbers that are close by, and dissimilar words with numbers that are far away from each other. A sentence embedding does the same thing, but associating a vector to every sentence. Similarity is a way to measure how similar two words (or', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
+ {'id': 'doc_1', 'text': 'Sentence embeddings\n\nSo word embeddings seem to be pretty useful, but in reality, human language is much more complicated than simply a bunch of words put together. Human language has structure, sentences, etc. How would one be able to represent, for instance, a sentence? Well, here’s an idea. How about the sums of scores of all the words? For example, say we have a word embedding that assigns the following scores to these words:\n\nNo: [1,0,0,0]\n\nI: [0,2,0,0]\n\nAm: [-1,0,1,0]\n\nGood: [0,0,1,3]', 'title': 'Text Embeddings', 'url': 'https://docs.cohere.com/docs/text-embeddings'}
+ {'id': 'doc_2', 'text': 'This is where sentence embeddings come into play. A sentence embedding is just like a word embedding, except it associates every sentence with a vector full of numbers, in a coherent way. By coherent, I mean that it satisfies similar properties as a word embedding. For instance, similar sentences are assigned to similar vectors, different sentences are assigned to different vectors, and most importantly, each of the coordinates of the vector identifies some (whether clear or obscure) property of', 'title': 'Text Embeddings', 'url': 'https://docs.cohere.com/docs/text-embeddings'}
+
+ ----------------------------------------------------------------------------------------------------
+
+ Retrieving information...
+ Chatbot:
+ The similarities between words and sentences are both quantitative measures of how close the two given items are. There are two types of similarities that can be defined: dot product similarity, and cosine similarity. These methods can determine how similar two words, or sentences, are.
+
+ CITATIONS:
+ start=54 end=75 text='quantitative measures' document_ids=['doc_0']
+ start=79 end=88 text='how close' document_ids=['doc_0']
+ start=124 end=133 text='two types' document_ids=['doc_0', 'doc_4']
+ start=171 end=193 text='dot product similarity' document_ids=['doc_0', 'doc_4']
+ start=199 end=217 text='cosine similarity.' document_ids=['doc_0', 'doc_4']
+ start=236 end=257 text='determine how similar' document_ids=['doc_0', 'doc_4']
+
+ DOCUMENTS:
+ {'id': 'doc_0', 'text': 'Now that we know embeddings quite well, let’s move on to using them to find similarities. There are two types of similarities we’ll define in this post: dot product similarity and cosine similarity. Both are very similar and very useful to determine if two words (or sentences) are similar.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
+ {'id': 'doc_1', 'text': 'But let me add some numbers to this reasoning to make it more clear. Imagine that we calculate similarities for the words in each sentence, and we get the following:\n\nThis similarity makes sense in the following ways:\n\nThe similarity between each word and itself is 1.\n\nThe similarity between any irrelevant word (“the”, “of”, etc.) and any other word is 0.\n\nThe similarity between “bank” and “river” is 0.11.\n\nThe similarity between “bank” and “money” is 0.25.', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
+ {'id': 'doc_2', 'text': 'And the results are:\n\nThe similarity between sentences 1 and 2: 6738.2858668486715\n\nThe similarity between sentences 1 and 3: -122.22666955510499\n\nThe similarity between sentences 2 and 3: -3.494608113647928\n\nThese results certainly confirm our predictions. The similarity between sentences 1 and 2 is 6738, which is high. The similarities between sentences 1 and 3, and 2 and 3, are -122 and -3.5 (dot products are allowed to be negative too!), which are much lower.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
+ {'id': 'doc_3', 'text': 'But let me add some numbers to this reasoning to make it more clear. Imagine that we calculate similarities for the words in each sentence, and we get the following:\n\nThis similarity makes sense in the following ways:\n\nThe similarity between each word and itself is 1.\n\nThe similarity between any irrelevant word (“the”, “of”, etc.) and any other word is 0.\n\nThe similarity between “bank” and “river” is 0.11.\n\nThe similarity between “bank” and “money” is 0.25.', 'title': 'The Attention Mechanism', 'url': 'https://docs.cohere.com/docs/the-attention-mechanism'}
+ {'id': 'doc_4', 'text': 'Now that we know embeddings quite well, let’s move on to using them to find similarities. There are two types of similarities we’ll define in this post: dot product similarity and cosine similarity. Both are very similar and very useful to determine if two words (or sentences) are similar.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
+ {'id': 'doc_5', 'text': 'And the results are:\n\nThe similarity between sentences 1 and 2: 6738.2858668486715\n\nThe similarity between sentences 1 and 3: -122.22666955510499\n\nThe similarity between sentences 2 and 3: -3.494608113647928\n\nThese results certainly confirm our predictions. The similarity between sentences 1 and 2 is 6738, which is high. The similarities between sentences 1 and 3, and 2 and 3, are -122 and -3.5 (dot products are allowed to be negative too!), which are much lower.', 'title': 'Similarity Between Words and Sentences', 'url': 'https://docs.cohere.com/docs/similarity-between-words-and-sentences'}
+
+ ----------------------------------------------------------------------------------------------------
+
+ Ending chat.
+
+
+
+```python
+
```
diff --git a/fern/pages/cookbooks/rerank-demo.mdx b/fern/pages/cookbooks/rerank-demo.mdx
index d656ba614..93c10fcd4 100644
--- a/fern/pages/cookbooks/rerank-demo.mdx
+++ b/fern/pages/cookbooks/rerank-demo.mdx
@@ -1,5 +1,5 @@
---
-title: Learn How Cohere's Rerank Models Work
+title: Demo of Rerank
slug: /page/rerank-demo
description: "This page contains a basic tutorial on how Cohere's ReRank models work and how to use them."
@@ -10,9 +10,11 @@ keywords: "Cohere, ReRank"
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-In the past months, we engineered a novel relevance endpoint that takes a query and a list of documents and predicts the relevance between the query and each document.
+
+
+
+In the past months, we engineered a novel relevance endpoint that takes a query and a list of documents and predicts the relevance between the query and each document.
It can be used in a two-stage retrieval setup: First you take the user question, and retrieve the top-100 documents from your collection by either using lexical search or semantic search.
@@ -22,34 +24,36 @@ In our benchmarks across 20 datasets, we **saw significant improvements compared
We will demonstrate the rerank endpoint in this notebook.
-```python PYTHON
-!pip install "cohere<5"
-```
-```txt title="Output"
-[33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
-[0mRequirement already satisfied: cohere<5 in /opt/homebrew/lib/python3.9/site-packages (4.45)
-Requirement already satisfied: aiohttp<4.0,>=3.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (3.8.1)
-Requirement already satisfied: backoff<3.0,>=2.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (2.2.1)
-Requirement already satisfied: fastavro<2.0,>=1.8 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (1.9.3)
-Requirement already satisfied: importlib_metadata<7.0,>=6.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (6.6.0)
-Requirement already satisfied: requests<3.0.0,>=2.25.0 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from cohere<5) (2.28.2)
-Requirement already satisfied: urllib3<3,>=1.26 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from cohere<5) (1.26.14)
-Requirement already satisfied: attrs>=17.3.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (22.1.0)
-Requirement already satisfied: charset-normalizer<3.0,>=2.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (2.0.12)
-Requirement already satisfied: multidict<7.0,>=4.5 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (6.0.2)
-Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (4.0.2)
-Requirement already satisfied: yarl<2.0,>=1.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.8.1)
-Requirement already satisfied: frozenlist>=1.1.1 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.3.1)
-Requirement already satisfied: aiosignal>=1.1.2 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.2.0)
-Requirement already satisfied: zipp>=0.5 in /opt/homebrew/lib/python3.9/site-packages (from importlib_metadata<7.0,>=6.0->cohere<5) (3.15.0)
-Requirement already satisfied: idna<4,>=2.5 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from requests<3.0.0,>=2.25.0->cohere<5) (3.4)
-Requirement already satisfied: certifi>=2017.4.17 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from requests<3.0.0,>=2.25.0->cohere<5) (2022.12.7)
-[33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
-[0m
+
+
+```python
+!pip install "cohere<5"
```
-```python PYTHON
+ [33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
+ [0mRequirement already satisfied: cohere<5 in /opt/homebrew/lib/python3.9/site-packages (4.45)
+ Requirement already satisfied: aiohttp<4.0,>=3.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (3.8.1)
+ Requirement already satisfied: backoff<3.0,>=2.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (2.2.1)
+ Requirement already satisfied: fastavro<2.0,>=1.8 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (1.9.3)
+ Requirement already satisfied: importlib_metadata<7.0,>=6.0 in /opt/homebrew/lib/python3.9/site-packages (from cohere<5) (6.6.0)
+ Requirement already satisfied: requests<3.0.0,>=2.25.0 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from cohere<5) (2.28.2)
+ Requirement already satisfied: urllib3<3,>=1.26 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from cohere<5) (1.26.14)
+ Requirement already satisfied: attrs>=17.3.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (22.1.0)
+ Requirement already satisfied: charset-normalizer<3.0,>=2.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (2.0.12)
+ Requirement already satisfied: multidict<7.0,>=4.5 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (6.0.2)
+ Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (4.0.2)
+ Requirement already satisfied: yarl<2.0,>=1.0 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.8.1)
+ Requirement already satisfied: frozenlist>=1.1.1 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.3.1)
+ Requirement already satisfied: aiosignal>=1.1.2 in /opt/homebrew/lib/python3.9/site-packages (from aiohttp<4.0,>=3.0->cohere<5) (1.2.0)
+ Requirement already satisfied: zipp>=0.5 in /opt/homebrew/lib/python3.9/site-packages (from importlib_metadata<7.0,>=6.0->cohere<5) (3.15.0)
+ Requirement already satisfied: idna<4,>=2.5 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from requests<3.0.0,>=2.25.0->cohere<5) (3.4)
+ Requirement already satisfied: certifi>=2017.4.17 in /Users/elliottchoi/Library/Python/3.9/lib/python/site-packages (from requests<3.0.0,>=2.25.0->cohere<5) (2022.12.7)
+ [33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
+ [0m
+
+
+```python
import cohere
import requests
import numpy as np
@@ -58,11 +62,14 @@ from typing import List
from pprint import pprint
```
-```python PYTHON
-API_KEY = ""
+
+```python
+# Set up your cohere client
+API_KEY = ""
co = cohere.Client(API_KEY)
MODEL_NAME = "rerank-english-v3.0" # another option is rerank-multilingual-02
+# Example query and passages (data taken from http://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz)
query = "What is the capital of the United States?"
docs = [
"Carson City is the capital city of the American state of Nevada. At the 2010 United States Census, Carson City had a population of 55,274.",
@@ -70,7 +77,7 @@ docs = [
"Charlotte Amalie is the capital and largest city of the United States Virgin Islands. It has about 20,000 people. The city is on the island of Saint Thomas.",
"Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district. The President of the USA and many major national government offices are in the territory. This makes it the political center of the United States of America.",
"West Virginia is a state in the Appalachian region of the United States. Its capital and largest city is Charleston. It is often abbreviated W. Va. or simply WV.",
- "Capital punishment has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.",
+ "Capital punishment (the death penalty) has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.",
"North Dakota is a state in the United States. 672,591 people lived in North Dakota in the year 2010. The capital and seat of government is Bismarck.",
"Kentucky is a state in the United States. Its capital is Frankfort. It touches the states of Missouri (by the Mississippi River), Illinois, Indiana, Ohio, West Virginia (by the Ohio River), Tennessee and Virginia. There are many rivers in Kentucky",
"Micronesia, officially the Federated States of Micronesia, is an island nation in the Pacific Ocean, northeast of Papua New Guinea. The country is a sovereign state in free association with the United States. The capital city of Federated States of Micronesia is Palikir.",
@@ -78,10 +85,12 @@ docs = [
```
## Using the Endpoint
-
In the following cell we will call rerank to rank `docs` based on how relevant they are with `query`.
-```python PYTHON
+
+
+
+```python
results = co.rerank(query=query, model=MODEL_NAME, documents=docs, top_n=3) # Change top_n to change the number of results returned. If top_n is not passed, all results will be returned.
for idx, r in enumerate(results):
print(f"Document Rank: {idx + 1}, Document Index: {r.index}")
@@ -90,45 +99,47 @@ for idx, r in enumerate(results):
print("\n")
```
-```txt title="Output"
-Document Rank: 1, Document Index: 3
-Document: Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district. The President of the USA and many major national government offices are in the territory. This makes it the political center of the United States of America.
-Relevance Score: 1.00
+ Document Rank: 1, Document Index: 3
+ Document: Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district. The President of the USA and many major national government offices are in the territory. This makes it the political center of the United States of America.
+ Relevance Score: 1.00
+
+
+ Document Rank: 2, Document Index: 5
+ Document: Capital punishment (the death penalty) has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.
+ Relevance Score: 0.75
+
+
+ Document Rank: 3, Document Index: 1
+ Document: The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean that are a political division controlled by the United States. Its capital is Saipan.
+ Relevance Score: 0.09
+
+
-Document Rank: 2, Document Index: 5
-Document: Capital punishment has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.
-Relevance Score: 0.75
-
-
-Document Rank: 3, Document Index: 1
-Document: The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean that are a political division controlled by the United States. Its capital is Saipan.
-Relevance Score: 0.09
-```
+## Search on Wikipedia - End2end demo
+The following is an example how to use this model end-to-end to search over the Simple English Wikipedia, which consists of about 500k passages.
-## Search on Wikipedia - End2end demo
+We use BM25 lexical search to retrieve the top-100 passages matching the query and then send these 100 passages and the query to our rerank endpoint to get a re-ranked list. We output the top-3 hits according to BM25 lexical search (as used by e.g. Elasticsearch) and the re-ranked list from our endpoint.
-The following is an example how to use this model end-to-end to search over the Simple English Wikipedia, which consists of about 500k passages.
-We use BM25 lexical search to retrieve the top-100 passages matching the query and then send these 100 passages and the query to our rerank endpoint to get a re-ranked list. We output the top-3 hits according to BM25 lexical search (as used by e.g. Elasticsearch) and the re-ranked list from our endpoint.
-```python PYTHON
+```python
!pip install -U rank_bm25
```
-```txt title="Output"
-[33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
-[0mCollecting rank_bm25
- Downloading rank_bm25-0.2.2-py3-none-any.whl.metadata (3.2 kB)
-Requirement already satisfied: numpy in /opt/homebrew/lib/python3.9/site-packages (from rank_bm25) (1.23.5)
-Downloading rank_bm25-0.2.2-py3-none-any.whl (8.6 kB)
-Installing collected packages: rank_bm25
-[33m DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
-[0m[33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
-[0mSuccessfully installed rank_bm25-0.2.2
-```
+ [33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
+ [0mCollecting rank_bm25
+ Downloading rank_bm25-0.2.2-py3-none-any.whl.metadata (3.2 kB)
+ Requirement already satisfied: numpy in /opt/homebrew/lib/python3.9/site-packages (from rank_bm25) (1.23.5)
+ Downloading rank_bm25-0.2.2-py3-none-any.whl (8.6 kB)
+ Installing collected packages: rank_bm25
+ [33m DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
+ [0m[33mDEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621[0m[33m
+ [0mSuccessfully installed rank_bm25-0.2.2
+
-```python PYTHON
+
+```python
import json
import gzip
import os
@@ -138,38 +149,41 @@ import string
from tqdm.autonotebook import tqdm
```
-```txt title="Output"
-/var/folders/ww/ht8qwj2s7s799qnktblg6qhm0000gp/T/ipykernel_31832/1066443236.py:7: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
- from tqdm.autonotebook import tqdm
-```
+ /var/folders/ww/ht8qwj2s7s799qnktblg6qhm0000gp/T/ipykernel_31832/1066443236.py:7: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
+ from tqdm.autonotebook import tqdm
+
-```python PYTHON
-!wget http://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
-```
-```txt title="Output"
---2024-04-08 14:28:00-- http://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
-Resolving sbert.net (sbert.net)... 172.64.80.1, 2606:4700:130:436c:6f75:6466:6c61:7265
-Connecting to sbert.net (sbert.net)|172.64.80.1|:80... connected.
-HTTP request sent, awaiting response... 301 Moved Permanently
-Location: https://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz [following]
---2024-04-08 14:28:01-- https://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
-Connecting to sbert.net (sbert.net)|172.64.80.1|:443... connected.
-HTTP request sent, awaiting response... 301 Moved Permanently
-Location: https://public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/datasets/simplewiki-2020-11-01.jsonl.gz [following]
---2024-04-08 14:28:01-- https://public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/datasets/simplewiki-2020-11-01.jsonl.gz
-Resolving public.ukp.informatik.tu-darmstadt.de (public.ukp.informatik.tu-darmstadt.de)... 130.83.167.186
-Connecting to public.ukp.informatik.tu-darmstadt.de (public.ukp.informatik.tu-darmstadt.de)|130.83.167.186|:443... connected.
-HTTP request sent, awaiting response... 200 OK
-Length: 50223724 (48M) [application/octet-stream]
-Saving to: ‘simplewiki-2020-11-01.jsonl.gz’
-
-simplewiki-2020-11- 100%[===================>] 47.90M 5.78MB/s in 8.9s
-
-2024-04-08 14:28:11 (5.37 MB/s) - ‘simplewiki-2020-11-01.jsonl.gz’ saved [50223724/50223724]
+```python
+!wget http://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
```
-```python PYTHON
+ --2024-04-08 14:28:00-- http://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
+ Resolving sbert.net (sbert.net)... 172.64.80.1, 2606:4700:130:436c:6f75:6466:6c61:7265
+ Connecting to sbert.net (sbert.net)|172.64.80.1|:80... connected.
+ HTTP request sent, awaiting response... 301 Moved Permanently
+ Location: https://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz [following]
+ --2024-04-08 14:28:01-- https://sbert.net/datasets/simplewiki-2020-11-01.jsonl.gz
+ Connecting to sbert.net (sbert.net)|172.64.80.1|:443... connected.
+ HTTP request sent, awaiting response... 301 Moved Permanently
+ Location: https://public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/datasets/simplewiki-2020-11-01.jsonl.gz [following]
+ --2024-04-08 14:28:01-- https://public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/datasets/simplewiki-2020-11-01.jsonl.gz
+ Resolving public.ukp.informatik.tu-darmstadt.de (public.ukp.informatik.tu-darmstadt.de)... 130.83.167.186
+ Connecting to public.ukp.informatik.tu-darmstadt.de (public.ukp.informatik.tu-darmstadt.de)|130.83.167.186|:443... connected.
+ HTTP request sent, awaiting response... 200 OK
+ Length: 50223724 (48M) [application/octet-stream]
+ Saving to: ‘simplewiki-2020-11-01.jsonl.gz’
+
+ simplewiki-2020-11- 100%[===================>] 47.90M 5.78MB/s in 8.9s
+
+ 2024-04-08 14:28:11 (5.37 MB/s) - ‘simplewiki-2020-11-01.jsonl.gz’ saved [50223724/50223724]
+
+
+
+
+```python
+# As dataset, we use Simple English Wikipedia. Compared to the full English wikipedia, it has only
+# about 170k articles. We split these articles into paragraphs and encode them with the bi-encoder
wikipedia_filepath = 'simplewiki-2020-11-01.jsonl.gz'
passages = []
@@ -181,18 +195,23 @@ with gzip.open(wikipedia_filepath, 'rt', encoding='utf8') as fIn:
print("Passages:", len(passages))
```
-```txt title="Output"
-Passages: 509663
-```
+ Passages: 509663
-```python PYTHON
+
+
+```python
print(passages[0], passages[1])
```
Ted Cassidy (July 31, 1932 - January 16, 1979) was an American actor. He was best known for his roles as Lurch and Thing on "The Addams Family". Aileen Carol Wuornos Pralle (born Aileen Carol Pittman; February 29, 1956 – October 9, 2002) was an American serial killer. She was born in Rochester, Michigan. She confessed to killing six men in Florida and was executed in Florida State Prison by lethal injection for the murders. Wuornos said that the men she killed had raped her or tried to rape her while she was working as a prostitute.
-```python PYTHON
+
+```python
+# We compare the results to lexical search (keyword search). Here, we use
+# the BM25 algorithm which is implemented in the rank_bm25 package.
+
+# We lower case our text and remove stop-words from indexing
def bm25_tokenizer(text):
tokenized_doc = []
for token in text.lower().split():
@@ -210,11 +229,13 @@ for passage in tqdm(passages):
bm25 = BM25Okapi(tokenized_corpus)
```
-```
-100%|██████████| 509663/509663 [00:09<00:00, 51180.82it/s]
-```
+ 100%|██████████| 509663/509663 [00:09<00:00, 51180.82it/s]
+
-```python PYTHON
+
+```python
+# This function will search all wikipedia articles for passages that
+# answer the query. We then re-rank using our rerank endpoint
def search(query, top_k=3, num_candidates=100):
print("Input question:", query)
@@ -224,137 +245,136 @@ def search(query, top_k=3, num_candidates=100):
top_n = np.argpartition(bm25_scores, -num_candidates)[-num_candidates:]
bm25_hits = [{'corpus_id': idx, 'score': bm25_scores[idx]} for idx in top_n]
bm25_hits = sorted(bm25_hits, key=lambda x: x['score'], reverse=True)
-
+
print(f"Top-3 lexical search (BM25) hits")
for hit in bm25_hits[0:top_k]:
print("\t{:.3f}\t{}".format(hit['score'], passages[hit['corpus_id']].replace("\n", " ")))
-
+
#Add re-ranking
docs = [passages[hit['corpus_id']] for hit in bm25_hits]
-
+
print(f"\nTop-3 hits by rank-API ({len(bm25_hits)} BM25 hits re-ranked)")
results = co.rerank(query=query, model=MODEL_NAME, documents=docs, top_n=top_k)
for hit in results:
print("\t{:.3f}\t{}".format(hit.relevance_score, hit.document["text"].replace("\n", " ")))
```
-```python PYTHON
+
+```python
search(query = "What is the capital of the United States?")
```
-```txt title="Output"
-Input question: What is the capital of the United States?
-Top-3 lexical search (BM25) hits
- 16.264 Capital punishment has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.
- 15.124 In 1783, it was the capital of the United States for a few months.
- 14.476 New York was the capital of the United States under the Articles of Confederation from 1785 to 1788. When the US Constitution was made, it stayed as the capital from 1789 until 1790. In 1789, the first President of the United States, George Washington, was inaugurated; the first United States Congress and the Supreme Court of the United States each met for the first time, and the United States Bill of Rights was written, all at Federal Hall on Wall Street. By 1790, New York grew bigger than Philadelphia, so it become the biggest city in the United States. By the end of 1790, because of the Residence Act, Philadelphia became the new capital.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.999 Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district. The President of the USA and many major national government offices are in the territory. This makes it the political center of the United States of America.
- 0.994 New York was the capital of the United States under the Articles of Confederation from 1785 to 1788. When the US Constitution was made, it stayed as the capital from 1789 until 1790. In 1789, the first President of the United States, George Washington, was inaugurated; the first United States Congress and the Supreme Court of the United States each met for the first time, and the United States Bill of Rights was written, all at Federal Hall on Wall Street. By 1790, New York grew bigger than Philadelphia, so it become the biggest city in the United States. By the end of 1790, because of the Residence Act, Philadelphia became the new capital.
- 0.993 As the national capital of the United States, Washington, D.C. has numerous media outlets in various mediums. Some of these media are known throughout the United States, including "The Washington Post" and various broadcasting networks headquartered in D.C.
-```
+ Input question: What is the capital of the United States?
+ Top-3 lexical search (BM25) hits
+ 16.264 Capital punishment (the death penalty) has existed in the United States since before the United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states. The federal government (including the United States military) also uses capital punishment.
+ 15.124 In 1783, it was the capital of the United States for a few months.
+ 14.476 New York was the capital of the United States under the Articles of Confederation from 1785 to 1788. When the US Constitution was made, it stayed as the capital from 1789 until 1790. In 1789, the first President of the United States, George Washington, was inaugurated; the first United States Congress and the Supreme Court of the United States each met for the first time, and the United States Bill of Rights was written, all at Federal Hall on Wall Street. By 1790, New York grew bigger than Philadelphia, so it become the biggest city in the United States. By the end of 1790, because of the Residence Act, Philadelphia became the new capital.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.999 Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district. The President of the USA and many major national government offices are in the territory. This makes it the political center of the United States of America.
+ 0.994 New York was the capital of the United States under the Articles of Confederation from 1785 to 1788. When the US Constitution was made, it stayed as the capital from 1789 until 1790. In 1789, the first President of the United States, George Washington, was inaugurated; the first United States Congress and the Supreme Court of the United States each met for the first time, and the United States Bill of Rights was written, all at Federal Hall on Wall Street. By 1790, New York grew bigger than Philadelphia, so it become the biggest city in the United States. By the end of 1790, because of the Residence Act, Philadelphia became the new capital.
+ 0.993 As the national capital of the United States, Washington, D.C. has numerous media outlets in various mediums. Some of these media are known throughout the United States, including "The Washington Post" and various broadcasting networks headquartered in D.C.
+
+
-```python PYTHON
+```python
search(query = "Number countries Europe")
```
-```txt title="Output"
-Input question: Number countries Europe
-Top-3 lexical search (BM25) hits
- 16.963 ECoHR' has a number of judges. The number of judges is seven normally but at the case of dealing a great issue, the number will be 21 and the judges are equally from member countries of the Council of Europe. At present, there are forty seven member countries of the Council of Europe. Each country may have one judge in the ECoHR. But, judges work independently for the ECoHR, and not for their country.
- 14.560 Most countries in Europe, and a few countries in Asia, have made some or all synthetic cannabinoids illegal.
- 14.165 Many of these countries were members of the Western European Union. Many, such as Norway, are also in Northern Europe or in Central Europe or Southern Europe.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.997 There are at least 43 countries in Europe (the European identities of 5 transcontinental countries:Cyprus, Georgia, Kazakhstan, Russia and Turkey are disputed). Most of these countries are members of the European Union.
- 0.987 Within these regions, there are up to 48 independent European countries (with the identities of 5 transcontinental countries being disputed). The largest is the Russian Federation, which covers 39% of Europe.
- 0.981 Europe, the planet's 6th largest continent, includes 47 countries and assorted dependencies, islands and territories.
-```
+ Input question: Number countries Europe
+ Top-3 lexical search (BM25) hits
+ 16.963 ECoHR' has a number of judges. The number of judges is seven normally but at the case of dealing a great issue, the number will be 21 and the judges are equally from member countries of the Council of Europe. At present, there are forty seven member countries of the Council of Europe. Each country may have one judge in the ECoHR. But, judges work independently for the ECoHR, and not for their country.
+ 14.560 Most countries in Europe, and a few countries in Asia, have made some or all synthetic cannabinoids illegal.
+ 14.165 Many of these countries were members of the Western European Union. Many, such as Norway, are also in Northern Europe or in Central Europe or Southern Europe.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.997 There are at least 43 countries in Europe (the European identities of 5 transcontinental countries:Cyprus, Georgia, Kazakhstan, Russia and Turkey are disputed). Most of these countries are members of the European Union.
+ 0.987 Within these regions, there are up to 48 independent European countries (with the identities of 5 transcontinental countries being disputed). The largest is the Russian Federation, which covers 39% of Europe.
+ 0.981 Europe, the planet's 6th largest continent, includes 47 countries and assorted dependencies, islands and territories.
+
+
-```python PYTHON
+```python
search(query = "Elon Musk year birth")
```
-```txt title="Output"
-Input question: Elon Musk year birth
-Top-3 lexical search (BM25) hits
- 22.568 Tesla, Inc. is a company based in Palo Alto, California which makes electric cars. It was started in 2003 by Martin Eberhard, Dylan Stott, and Elon Musk (who also co-founded PayPal and SpaceX and is the CEO of SpaceX). Eberhard no longer works there. Today, Elon Musk is the Chief Executive Officer (CEO). It started selling its first car, the Roadster in 2008.
- 20.492 Elon Musk complained via Twitter about Los Angeles traffic and the same day, December 17, 2016, founded the company. It built a short test tunnel in Los Angeles.
- 20.448 At the end of 2016, Musk founded The Boring Company which focuses on tunnelling and infrastructure. He mentioned Los Angeles traffic as the reason for starting this company. In March 2017 Elon Musk announced he has started another company which aims to merge human brains and computers, it is called Neuralink.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.994 Elon Reeve Musk (born June 28, 1971) is a businessman and philanthropist. He was born in South Africa. He moved to Canada and later became an American citizen. Musk is the current CEO & Chief Product Architect of Tesla Motors, a company that makes electric vehicles. He is also the CEO of Solar City, a company that makes solar panels, and the CEO & CTO of SpaceX, an aerospace company. In August 2020, Bloomberg ranked Musk third among the richest people on the planet with net worth to be $115.4 billion.
- 0.602 Elon Musk and his brother started Zip2, a software company, in 1995. In 1999 he sold it and became a millionaire. He then started X.com, which merged with the company to make PayPal. X.com was then renamed to PayPal, and he focused on growing that part of the company. He then started SpaceX and became the CEO of Tesla.
- 0.474 In early 2002, Musk was seeking workers for his new space company, soon to be named SpaceX. Musk found a rocket engineer Tom Mueller (later SpaceX's CTO of Propulsion). He agreed to work for Musk. That was how SpaceX was born. The first headquarters of SpaceX was in a warehouse in El Segundo, California. The company has grown rapidly since it was founded in 2002, growing from 160 workers in November 2005 to 1,100 in 2010, 3,800 workers and contractors by October 2013, nearly 5,000 by late 2015, and about 6,000 in April 2017.
-```
+ Input question: Elon Musk year birth
+ Top-3 lexical search (BM25) hits
+ 22.568 Tesla, Inc. is a company based in Palo Alto, California which makes electric cars. It was started in 2003 by Martin Eberhard, Dylan Stott, and Elon Musk (who also co-founded PayPal and SpaceX and is the CEO of SpaceX). Eberhard no longer works there. Today, Elon Musk is the Chief Executive Officer (CEO). It started selling its first car, the Roadster in 2008.
+ 20.492 Elon Musk complained via Twitter about Los Angeles traffic and the same day, December 17, 2016, founded the company. It built a short test tunnel in Los Angeles.
+ 20.448 At the end of 2016, Musk founded The Boring Company which focuses on tunnelling and infrastructure. He mentioned Los Angeles traffic as the reason for starting this company. In March 2017 Elon Musk announced he has started another company which aims to merge human brains and computers, it is called Neuralink.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.994 Elon Reeve Musk (born June 28, 1971) is a businessman and philanthropist. He was born in South Africa. He moved to Canada and later became an American citizen. Musk is the current CEO & Chief Product Architect of Tesla Motors, a company that makes electric vehicles. He is also the CEO of Solar City, a company that makes solar panels, and the CEO & CTO of SpaceX, an aerospace company. In August 2020, Bloomberg ranked Musk third among the richest people on the planet with net worth to be $115.4 billion.
+ 0.602 Elon Musk and his brother started Zip2, a software company, in 1995. In 1999 he sold it and became a millionaire. He then started X.com, which merged with the company to make PayPal. X.com was then renamed to PayPal, and he focused on growing that part of the company. He then started SpaceX and became the CEO of Tesla.
+ 0.474 In early 2002, Musk was seeking workers for his new space company, soon to be named SpaceX. Musk found a rocket engineer Tom Mueller (later SpaceX's CTO of Propulsion). He agreed to work for Musk. That was how SpaceX was born. The first headquarters of SpaceX was in a warehouse in El Segundo, California. The company has grown rapidly since it was founded in 2002, growing from 160 workers in November 2005 to 1,100 in 2010, 3,800 workers and contractors by October 2013, nearly 5,000 by late 2015, and about 6,000 in April 2017.
+
-```python PYTHON
+
+```python
search(query = "Which US president was killed?")
```
-```txt title="Output"
-Input question: Which US president was killed?
-Top-3 lexical search (BM25) hits
- 11.966 He came into office when the previous president, Cyprien Ntaryamira, was killed in a plane crash. It was an assassination in which the Rwandan president Juvénal Habyarimana was also killed. Ntibantunganya left office when he was deposed by Pierre Buyoya in a military coup of 1996.
- 11.697 Burr killed Alexander Hamilton in a duel in 1804, when Burr was still Vice President.
- 11.482 After President James A. Garfield died, vice-president Chester Arthur replaced him. The man who killed him expected the new President to pardon him. This did not happen.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.984 James Abram Garfield (November 19, 1831 - September 19, 1881) was the 20th (1881) President of the United States and the 2nd President to be assassinated (killed while in office). President Garfield was in office from March to September of 1881. He was in office for a total of six months and fifteen days. For almost half that time he was bedridden as a result of an attempt to kill him. He was shot on July 2 and finally died in September the same year he got into office.
- 0.976 President William McKinley was killed by anarchist Leon Czolgosz because Czolgosz believed president McKinley was against good working people, he considered McKinley responsible for falsifying the reasons for the war, and approving and waging an illegal, devastating Philippines war.
- 0.916 On the night that President Abraham Lincoln was killed, someone also tried to kill Seward. For the rest of his life, Seward had scars on his face from the attack. Later, the man who attacked him was caught and put to death.
-```
+ Input question: Which US president was killed?
+ Top-3 lexical search (BM25) hits
+ 11.966 He came into office when the previous president, Cyprien Ntaryamira, was killed in a plane crash. It was an assassination in which the Rwandan president Juvénal Habyarimana was also killed. Ntibantunganya left office when he was deposed by Pierre Buyoya in a military coup of 1996.
+ 11.697 Burr killed Alexander Hamilton in a duel in 1804, when Burr was still Vice President.
+ 11.482 After President James A. Garfield died, vice-president Chester Arthur replaced him. The man who killed him expected the new President to pardon him. This did not happen.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.984 James Abram Garfield (November 19, 1831 - September 19, 1881) was the 20th (1881) President of the United States and the 2nd President to be assassinated (killed while in office). President Garfield was in office from March to September of 1881. He was in office for a total of six months and fifteen days. For almost half that time he was bedridden as a result of an attempt to kill him. He was shot on July 2 and finally died in September the same year he got into office.
+ 0.976 President William McKinley was killed by anarchist Leon Czolgosz because Czolgosz believed president McKinley was against good working people, he considered McKinley responsible for falsifying the reasons for the war, and approving and waging an illegal, devastating Philippines war.
+ 0.916 On the night that President Abraham Lincoln was killed, someone also tried to kill Seward. For the rest of his life, Seward had scars on his face from the attack. Later, the man who attacked him was caught and put to death.
-```python PYTHON
+
+
+```python
search(query="When is Chinese New Year")
```
-```txt title="Output"
-Input question: When is Chinese New Year
-Top-3 lexical search (BM25) hits
- 18.606 Today in China the Gregorian calendar is used for most activities. At the same time, the Chinese calendar is still used for traditional Chinese holidays like Chinese New Year or Lunar New Year.
- 18.151 Before that, the holiday was usually just called the "NewYear". Because the traditional Chinese calendar is mostly based on the changes in the moon, the Chinese New Year is also known in English as the "Lunar New Year" or "Chinese Lunar New Year". This name comes from "Luna", an old Latin name for the moon. The Indonesian name for the holiday is Imlek, which comes from the Hokkien word for the old Chinese calendar and is therefore also like saying "Lunar New Year".
- 18.011 Spring Festival is the Chinese New Year.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.999 Chinese New Year, known in China as the SpringFestival and in Singapore as the LunarNewYear, is a holiday on and around the new moon on the first day of the year in the traditional Chinese calendar. This calendar is based on the changes in the moon and is only sometimes changed to fit the seasons of the year based on how the Earth moves around the sun. Because of this, Chinese New Year is never on January1. It moves around between January21 and February20.
- 0.997 Chinese New Year always starts on a new moon, when the Moon is between the Earth and Sun and it looks all dark in the night sky. Because new moons happen about every 29.53 days but the year set by Pope GregoryXIII is 365.2425 days long, the Chinese holiday moves to different days each year. The Chinese calendar adds a 13th month every so often to keep the seasons in the right place, so the first day of the new year always happens between January21 and February20 on the 2nd or 3rd new moon after the 1st day of winter. The chart on the right gives the day of each Chinese New Year from 1996 to 2031.
- 0.996 Chinese New Year lasts fifteen days, including one week as a national holiday. It starts with the first day of the Chinese lunar year and ends with the full moon fifteen days later. It is always in the middle of winter, but is called the Spring Festival in Chinese because Chinese seasons are a little different from English ones. On the first day of the Chinese New Year, people call on friends and relatives. Because most people watch the special performances on CCTV all the night on New Year's Eve and don't go to bed until 12:00 AM, they usually get up later in the next day. The fifth day of the Chinese New Year is the day to welcome the god of Wealth (Chinese:财神爷), many people make and eat dumplings (Chinese:饺子. Pinyin: Jaozi). They believe that dumplings can hold the god of Wealth and bring luck. The last day of the Chinese New Year is the Lantern Festival. On this day, the moon becomes the full moon. People go out and watch the lantern festivals everywhere. After that, they eat sweet dumpling (Chinese:汤圆,元宵), a kind of dumpling which is round and looks like the full moon.
-```
+ Input question: When is Chinese New Year
+ Top-3 lexical search (BM25) hits
+ 18.606 Today in China the Gregorian calendar is used for most activities. At the same time, the Chinese calendar is still used for traditional Chinese holidays like Chinese New Year or Lunar New Year.
+ 18.151 Before that, the holiday was usually just called the "NewYear". Because the traditional Chinese calendar is mostly based on the changes in the moon, the Chinese New Year is also known in English as the "Lunar New Year" or "Chinese Lunar New Year". This name comes from "Luna", an old Latin name for the moon. The Indonesian name for the holiday is Imlek, which comes from the Hokkien word for the old Chinese calendar and is therefore also like saying "Lunar New Year".
+ 18.011 Spring Festival is the Chinese New Year.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.999 Chinese New Year, known in China as the SpringFestival and in Singapore as the LunarNewYear, is a holiday on and around the new moon on the first day of the year in the traditional Chinese calendar. This calendar is based on the changes in the moon and is only sometimes changed to fit the seasons of the year based on how the Earth moves around the sun. Because of this, Chinese New Year is never on January1. It moves around between January21 and February20.
+ 0.997 Chinese New Year always starts on a new moon, when the Moon is between the Earth and Sun and it looks all dark in the night sky. Because new moons happen about every 29.53 days but the year set by Pope GregoryXIII is 365.2425 days long, the Chinese holiday moves to different days each year. The Chinese calendar adds a 13th month every so often to keep the seasons in the right place, so the first day of the new year always happens between January21 and February20 on the 2nd or 3rd new moon after the 1st day of winter. The chart on the right gives the day of each Chinese New Year from 1996 to 2031.
+ 0.996 Chinese New Year lasts fifteen days, including one week as a national holiday. It starts with the first day of the Chinese lunar year and ends with the full moon fifteen days later. It is always in the middle of winter, but is called the Spring Festival in Chinese because Chinese seasons are a little different from English ones. On the first day of the Chinese New Year, people call on friends and relatives. Because most people watch the special performances on CCTV all the night on New Year's Eve and don't go to bed until 12:00 AM, they usually get up later in the next day. The fifth day of the Chinese New Year is the day to welcome the god of Wealth (Chinese:财神爷), many people make and eat dumplings (Chinese:饺子. Pinyin: Jaozi). They believe that dumplings can hold the god of Wealth and bring luck. The last day of the Chinese New Year is the Lantern Festival. On this day, the moon becomes the full moon. People go out and watch the lantern festivals everywhere. After that, they eat sweet dumpling (Chinese:汤圆,元宵), a kind of dumpling which is round and looks like the full moon.
-```python PYTHON
+
+
+```python
search(query="How many people live in Paris")
```
-```txt title="Output"
-Input question: How many people live in Paris
-Top-3 lexical search (BM25) hits
- 16.277 Live à Paris (English: "Live in Paris") is a live album by Canadian singer Céline Dion.
- 15.173 Île-de-France is a region of France. The capital city is Paris. It is also the capital city of France. In 2013 about 12 million people lived in the region. About 2.1 million people live in the city of Paris.
- 14.666 Gennevilliers is a town in France near Paris. It is in the region Île-de-France and the department of Hauts-de-Seine. About 41,000 people live there.
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.999 Paris (nicknamed the ""City of light"") is the capital city of France, and the largest city in France. The area is , and around 2.15 million people live there. If suburbs are counted, the population of the Paris area rises to 12 million people.
- 0.987 Île-de-France is a region of France. The capital city is Paris. It is also the capital city of France. In 2013 about 12 million people lived in the region. About 2.1 million people live in the city of Paris.
- 0.602 Essonne is a department to the south of Paris in the Île-de-France region. Its prefecture is Évry. About 1,172,000 people live there (2006 estimation).
-```
+ Input question: How many people live in Paris
+ Top-3 lexical search (BM25) hits
+ 16.277 Live à Paris (English: "Live in Paris") is a live album by Canadian singer Céline Dion.
+ 15.173 Île-de-France is a region of France. The capital city is Paris. It is also the capital city of France. In 2013 about 12 million people lived in the region. About 2.1 million people live in the city of Paris.
+ 14.666 Gennevilliers is a town in France near Paris. It is in the region Île-de-France and the department of Hauts-de-Seine. About 41,000 people live there.
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.999 Paris (nicknamed the ""City of light"") is the capital city of France, and the largest city in France. The area is , and around 2.15 million people live there. If suburbs are counted, the population of the Paris area rises to 12 million people.
+ 0.987 Île-de-France is a region of France. The capital city is Paris. It is also the capital city of France. In 2013 about 12 million people lived in the region. About 2.1 million people live in the city of Paris.
+ 0.602 Essonne is a department to the south of Paris in the Île-de-France region. Its prefecture is Évry. About 1,172,000 people live there (2006 estimation).
+
-```python PYTHON
+
+```python
search(query="Who is the director of The Matrix?")
```
-```txt title="Output"
-Input question: Who is the director of The Matrix?
-Top-3 lexical search (BM25) hits
- 16.253 An inverse matrix is a matrix that, when multiplied by another matrix, equals the identity matrix. For example:
- 16.072 is an identity matrix. There is exactly one identity matrix for each square dimension set. An identity matrix is special because when multiplying any matrix by the identity matrix, the result is always the original matrix with no change.
- 15.353 First, the system needs to be turned into an augmented matrix. In an augmented matrix, each linear equation becomes a row. On one side of the augmented matrix, the coefficients of each term in the linear equation become numbers in the matrix. On the other side of the augmented matrix are the constant terms each linear equation is equal to. For this system, the augmented matrix is:
-
-Top-3 hits by rank-API (100 BM25 hits re-ranked)
- 0.995 The Matrix is a science fiction action movie that was made in 1999. It was written and directed by the Wachowski Brothers. The main actors in the movie are Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss, and Hugo Weaving. "The Matrix" was followed by two sequels: "The Matrix Reloaded" and "The Matrix Revolutions".
- 0.992 Helmut Bakaitis (born 26 September 1944) is a German-born Australian director, actor and screenwriter. He is known for his role as The Architect in "The Matrix" movie series. Bakaitis was born in Lauban, Lower Silesia, Germany (now Lubań, Poland). Bakaitis started teaching directing at Australian Academy of Dramatic Art (AADA).
- 0.804 The Matrix Revolutions is a 2003 movie that was written and directed by the Wachowski brothers. It is the sequel to "The Matrix Reloaded".
+ Input question: Who is the director of The Matrix?
+ Top-3 lexical search (BM25) hits
+ 16.253 An inverse matrix is a matrix that, when multiplied by another matrix, equals the identity matrix. For example:
+ 16.072 is an identity matrix. There is exactly one identity matrix for each square dimension set. An identity matrix is special because when multiplying any matrix by the identity matrix, the result is always the original matrix with no change.
+ 15.353 First, the system needs to be turned into an augmented matrix. In an augmented matrix, each linear equation becomes a row. On one side of the augmented matrix, the coefficients of each term in the linear equation become numbers in the matrix. On the other side of the augmented matrix are the constant terms each linear equation is equal to. For this system, the augmented matrix is:
+
+ Top-3 hits by rank-API (100 BM25 hits re-ranked)
+ 0.995 The Matrix is a science fiction action movie that was made in 1999. It was written and directed by the Wachowski Brothers. The main actors in the movie are Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss, and Hugo Weaving. "The Matrix" was followed by two sequels: "The Matrix Reloaded" and "The Matrix Revolutions".
+ 0.992 Helmut Bakaitis (born 26 September 1944) is a German-born Australian director, actor and screenwriter. He is known for his role as The Architect in "The Matrix" movie series. Bakaitis was born in Lauban, Lower Silesia, Germany (now Lubań, Poland). Bakaitis started teaching directing at Australian Academy of Dramatic Art (AADA).
+ 0.804 The Matrix Revolutions is a 2003 movie that was written and directed by the Wachowski brothers. It is the sequel to "The Matrix Reloaded".
-```
diff --git a/fern/pages/cookbooks/sql-agent.mdx b/fern/pages/cookbooks/sql-agent.mdx
index 028bddb7f..199fad891 100644
--- a/fern/pages/cookbooks/sql-agent.mdx
+++ b/fern/pages/cookbooks/sql-agent.mdx
@@ -1,9 +1,9 @@
---
-title: Build a SQL Agent with Cohere's LLM Platform
+title: SQL Agent
slug: /page/sql-agent
description: "This page contains a tutorial on how to build a SQL agent with Cohere's LLM platform."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, automatic SQL generation, code generation, AI agents"
---
@@ -14,601 +14,651 @@ import { CookbookHeader } from "../../components/cookbook-header";
authors={[
{
name: "Shaan Desai",
- imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg",
- },
+ imageSrc: "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg"
+ }
]}
/>
-
-## Motivation
+
+
+
-Enterprise customers often store and handle information in relational databases but querying such databases effectively requires bespoke knowledge of the underlying database structure as well as strong SQL coding skills. One way to address these challenges is to build an LLM agent capable of generating and executing SQL queries based on natural language. For example, if a user asks: `what are the top 4 rows in table X`, the agent should be able to generate `SELECT * FROM X LIMIT 4`, execute this query and return the output to the user.
+
+## Motivation
+Enterprise customers often store and handle information in relational databases but querying such databases effectively requires bespoke knowledge of the underlying database structure as well as strong SQL coding skills. One way to address these challenges is to build an LLM agent capable of generating and executing SQL queries based on natural language. For example If a user asks: ``what are the top 4 rows in table X``, the agent should be able to generate ``SELECT * FROM X LIMIT 4``, execute this query and return the output to the user.
## Objective
+In this notebook we explore how to setup a sql agent using langchain and Cohere models. We explore two ways to achieve this, one using the [create_sql_agent](https://api.python.langchain.com/en/latest/sql_agent/langchain_cohere.sql_agent.agent.create_sql_agent.html) abstraction from langchain-cohere, and another using the [Cohere ReAct Agent](https://github.com/langchain-ai/langchain-cohere/blob/main/libs/cohere/langchain_cohere/cohere_agent.py) to answer questions over SQL Databases. We show how this can be done seamlessly with langchain's existing SQLDBToolkit.
-In this notebook we explore how to setup a [Cohere ReAct Agent](https://github.com/langchain-ai/langchain-cohere/blob/main/libs/cohere/langchain_cohere/cohere_agent.py) to answer questions over SQL Databases. We show how this can be done seamlessly with langchain's existing [SQLDBToolkit](https://python.langchain.com/v0.1/docs/integrations/toolkits/sql_database/).
+The [create_sql_agent](https://api.python.langchain.com/en/latest/sql_agent/langchain_cohere.sql_agent.agent.create_sql_agent.html) option is recommended for most use cases and can be setup without much hassle.
-# Toolkit Setup [#sec_step0]
+## Table of Contents
-```python PYTHON
-from langchain.agents import AgentExecutor
-from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
-from langchain_core.prompts import ChatPromptTemplate
-from langchain_cohere.chat_models import ChatCohere
+- [SQL Agent with create_sql_agent](#sec_step0)
+- [SQL Agent using Cohere ReAct Agent](#sec_step1)
+ - [Toolkit Setup](#sec_step2)
+ - [SQL Agent](#sec_step3)
+ - [SQL Agent with context](#sec_step4)
+
+
+# SQL Agent with create_sql_agent
+
+
+
+
+```python
+from langchain_cohere import ChatCohere, create_sql_agent
from langchain_community.utilities.sql_database import SQLDatabase
-from langchain_community.agent_toolkits import SQLDatabaseToolkit
import os
-import json
```
-```python PYTHON
+
+```python
+####################################################################################################
+#
# Uncomment if you need to install the following packages
+#
+####################################################################################################
+
#!pip install --quiet langchain langchain_cohere langchain_experimental --upgrade
```
-Langchain already has a SQLDBToolkit that consists of 4 tools to handle SQL query generation, execution and validation. To use this, you simply need to define your LLM and DB and pass these into the Toolkit.
-
-These are the following tools:
-
-- 'sql_db_query': executes SQL code on the database
-- 'sql_db_schema': returns the schema of tables given the list of tables
-- 'sql_db_list_tables': lists the tables in the database
-- 'sql_db_query_checker': validates the SQL query
-```python PYTHON
+```python
# load the cohere api key
os.environ["COHERE_API_KEY"] = ""
```
-```python PYTHON
+
+```python
DB_NAME='Chinook.db'
MODEL="command-r-plus"
+
llm = ChatCohere(model=MODEL, temperature=0.1,verbose=True)
db = SQLDatabase.from_uri(f"sqlite:///{DB_NAME}")
-toolkit = SQLDatabaseToolkit(db=db, llm=llm)
-context = toolkit.get_context()
-tools = toolkit.get_tools()
-
-print('**List of pre-defined Langchain Tools**')
-print([tool.name for tool in tools])
```
-```txt title="Output"
-**List of pre-defined Langchain Tools**
-['sql_db_query', 'sql_db_schema', 'sql_db_list_tables', 'sql_db_query_checker']
+
+```python
+agent_executor = create_sql_agent(llm, db=db, verbose=True)
```
-# SQL Agent [#sec_step1]
+The create_sql_agent abstraction comes with access to the SQLDBTookit, and presents itself as an easy-to-use low-code solution to create an agent to answer questions over a db knowledge source.
+
-We follow the general cohere react agent setup in Langchain to build our SQL agent.
-```python PYTHON
-# define the prompt template
-prompt = ChatPromptTemplate.from_template("{input}")
-# instantiate the ReAct agent
-agent = create_cohere_react_agent(
- llm=llm,
- tools=tools,
- prompt=prompt,
-)
-agent_executor = AgentExecutor(agent=agent,
- tools=tools,
- verbose=True,
- return_intermediate_steps=True
- )
-```
-```python PYTHON
-output=agent_executor.invoke({
+```python
+agent_executor.invoke({
"input": 'what tables are available?',
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use the sql_db_list_tables tool to find out which tables are available.
-{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
-[0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.
-Grounded answer: The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.[0m
-
-[1m> Finished chain.[0m
-```
+
+
+ [1m> Entering new Cohere SQL Agent Executor chain...[0m
+ [32;1m[1;3m
+ Invoking: `sql_db_list_tables` with `{'tool_input': ''}`
+ responded: I will use the sql_db_list_tables tool to find out what tables are available in the database.
+
+ [0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3mThe following tables are available:
+ - Album
+ - Artist
+ - Customer
+ - Employee
+ - Genre
+ - Invoice
+ - InvoiceLine
+ - MediaType
+ - Playlist
+ - PlaylistTrack
+ - Track[0m
+
+ [1m> Finished chain.[0m
-```python PYTHON
-print(output['output'])
-```
-```txt title="Output"
-The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.
-```
-The agent uses the list_tables tool to effectively highlight all the tables in the DB.
-```python PYTHON
-output=agent_executor.invoke({
- "input": 'show the first row of the Playlist and Genre tables?',
-})
-```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will use the sql_db_schema tool to find the first row of the Playlist and Genre tables.
-{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Playlist, Genre'}}
-[0m[33;1m[1;3m
-CREATE TABLE "Genre" (
- "GenreId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("GenreId")
-)
+ {'input': 'what tables are available?',
+ 'output': 'The following tables are available:\n- Album\n- Artist\n- Customer\n- Employee\n- Genre\n- Invoice\n- InvoiceLine\n- MediaType\n- Playlist\n- PlaylistTrack\n- Track'}
-/*
-3 rows from Genre table:
-GenreId Name
-1 Rock
-2 Jazz
-3 Metal
-*/
-CREATE TABLE "Playlist" (
- "PlaylistId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("PlaylistId")
-)
+The agent is able to invoke the correct tool from the toolkit in order to find out the tables available in the db.
-/*
-3 rows from Playlist table:
-PlaylistId Name
-1 Music
-2 Movies
-3 TV Shows
-*/[0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: Here is the first row of the Genre table:
-| GenreId | Name |
-|---|---|
-| 1 | Rock |
+```python
+agent_executor.invoke({
+ "input": "who is the best customer? The customer who has spent the most money is the best. Please write and execute the correct sql query to answer this question, and give me the result!",
+})
+```
-Here is the first row of the Playlist table:
+
+
+ [1m> Entering new Cohere SQL Agent Executor chain...[0m
+ [32;1m[1;3m
+ Invoking: `sql_db_list_tables` with `{}`
+ responded: I will first list the tables in the database, then I will query the schema of the most relevant tables. After that, I will write and execute a SQL query to answer the user's question.
+
+ [0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3m
+ Invoking: `sql_db_schema` with `{'table_names': 'Customer, Invoice'}`
+ responded: The tables in the database are: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.
+
+ The most relevant tables for the user's question are Customer and Invoice. I will now query the schema of these tables.
+
+ [0m[33;1m[1;3m
+ CREATE TABLE "Customer" (
+ "CustomerId" INTEGER NOT NULL,
+ "FirstName" NVARCHAR(40) NOT NULL,
+ "LastName" NVARCHAR(20) NOT NULL,
+ "Company" NVARCHAR(80),
+ "Address" NVARCHAR(70),
+ "City" NVARCHAR(40),
+ "State" NVARCHAR(40),
+ "Country" NVARCHAR(40),
+ "PostalCode" NVARCHAR(10),
+ "Phone" NVARCHAR(24),
+ "Fax" NVARCHAR(24),
+ "Email" NVARCHAR(60) NOT NULL,
+ "SupportRepId" INTEGER,
+ PRIMARY KEY ("CustomerId"),
+ FOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")
+ )
+
+ /*
+ 3 rows from Customer table:
+ CustomerId FirstName LastName Company Address City State Country PostalCode Phone Fax Email SupportRepId
+ 1 Luís Gonçalves Embraer - Empresa Brasileira de Aeronáutica S.A. Av. Brigadeiro Faria Lima, 2170 São José dos Campos SP Brazil 12227-000 +55 (12) 3923-5555 +55 (12) 3923-5566 luisg@embraer.com.br 3
+ 2 Leonie Köhler None Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 +49 0711 2842222 None leonekohler@surfeu.de 5
+ 3 François Tremblay None 1498 rue Bélanger Montréal QC Canada H2G 1A7 +1 (514) 721-4711 None ftremblay@gmail.com 3
+ */
+
+
+ CREATE TABLE "Invoice" (
+ "InvoiceId" INTEGER NOT NULL,
+ "CustomerId" INTEGER NOT NULL,
+ "InvoiceDate" DATETIME NOT NULL,
+ "BillingAddress" NVARCHAR(70),
+ "BillingCity" NVARCHAR(40),
+ "BillingState" NVARCHAR(40),
+ "BillingCountry" NVARCHAR(40),
+ "BillingPostalCode" NVARCHAR(10),
+ "Total" NUMERIC(10, 2) NOT NULL,
+ PRIMARY KEY ("InvoiceId"),
+ FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
+ )
+
+ /*
+ 3 rows from Invoice table:
+ InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
+ 1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
+ 2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
+ 3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
+ */[0m[32;1m[1;3m
+ Invoking: `sql_db_query` with `{'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY TotalSpent DESC LIMIT 1;'}`
+ responded: The Customer table contains information about each customer's ID, name, company, address, city, state, country, postal code, phone number, fax, email, and support representative ID. The Invoice table contains information about each invoice's ID, customer ID, date, billing address, billing city, billing state, billing country, billing postal code, and total amount.
+
+ To answer the user's question, I will write a SQL query to find the customer who has spent the most money.
+
+ [0m[36;1m[1;3m[('Helena', 'Holý', 49.62)][0m[32;1m[1;3mThe best customer is Helena Holý, who has spent a total of 49.62.[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ {'input': 'who is the best customer? The customer who has spent the most money is the best. Please write and execute the correct sql query to answer this question, and give me the result!',
+ 'output': 'The best customer is Helena Holý, who has spent a total of 49.62.'}
+
+
+
+The agent is able to execute and query the relevant tables, including performing necessary table joins to answer the user query.
+
+
+# SQL Agent using Cohere ReAct Agent
+
+
+
+In the above section, we made use of an built in abstraction from langchain to perform question answering over a db knowledge source.
+Let us now build a similar agent from the ground up and understand better how the different components like tools, prompts and function calling work hand in hand to enable a succesful agent implementation.
+
+
+## Toolkit Setup
+
+
+
+
+```python
+from langchain.agents import AgentExecutor
+from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_cohere.chat_models import ChatCohere
+from langchain_community.utilities.sql_database import SQLDatabase
+from langchain_community.agent_toolkits import SQLDatabaseToolkit
+import os
+```
-| PlaylistId | Name |
-|---|---|
-| 1 | Music |
-Grounded answer: Here is the first row of the Genre table:
-| GenreId | Name |
-|---|---|
-| 1 | Rock |
+```python
+####################################################################################################
+#
+# Uncomment if you need to install the following packages
+#
+####################################################################################################
-Here is the first row of the Playlist table:
+#!pip install --quiet langchain langchain_cohere langchain_experimental --upgrade
+```
-| PlaylistId | Name |
-|---|---|
-| 1 | Music |[0m
+Langchain already has a SQLDBToolkit that consists of 4 tools to handle SQL query generation, execution and validation. To use this, you simply need to define your LLM and DB and pass these into the Toolkit.
-[1m> Finished chain.[0m
-```
+These are the following tools:
+- 'sql_db_query': executes SQL code on the database
+- 'sql_db_schema': returns the schema of tables given the list of tables
+- 'sql_db_list_tables': lists the tables in the database
+- 'sql_db_query_checker': validates the SQL query
-```python PYTHON
-print(output['output'])
-```
-```txt title="Output"
-Here is the first row of the Genre table:
-| GenreId | Name |
-|---|---|
-| 1 | Rock |
-Here is the first row of the Playlist table:
-| PlaylistId | Name |
-|---|---|
-| 1 | Music |
+```python
+# load the cohere api key
+os.environ["COHERE_API_KEY"] = ""
```
-Here we see that the tool takes a list of tables to query the sql_db_schema tool to retrieve the various schemas.
-```python PYTHON
-output=agent_executor.invoke({
- "input": 'which countries have the most invoices?',
-})
-```
+```python
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will search for the number of invoices per country and then write an answer.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC'}}
-[0m[36;1m[1;3mError: (sqlite3.OperationalError) no such table: invoices
-[SQL: SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC]
-(Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
-I received an error message. I will now use the sql_db_list_tables tool to find out the correct table name.
-{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
-[0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3m
-I found out that the correct table name is 'Invoice'. I will now rewrite my query and run it again.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}}
-[0m[36;1m[1;3mError: (sqlite3.OperationalError) no such column: country
-[SQL: SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC]
-(Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
-I received another error message. I will now use the sql_db_schema tool to find out the correct column name.
-{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Invoice'}}
-[0m[33;1m[1;3m
-CREATE TABLE "Invoice" (
- "InvoiceId" INTEGER NOT NULL,
- "CustomerId" INTEGER NOT NULL,
- "InvoiceDate" DATETIME NOT NULL,
- "BillingAddress" NVARCHAR(70),
- "BillingCity" NVARCHAR(40),
- "BillingState" NVARCHAR(40),
- "BillingCountry" NVARCHAR(40),
- "BillingPostalCode" NVARCHAR(10),
- "Total" NUMERIC(10, 2) NOT NULL,
- PRIMARY KEY ("InvoiceId"),
- FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
-)
+DB_NAME='Chinook.db'
+MODEL="command-r-plus"
-/*
-3 rows from Invoice table:
-InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
-1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
-2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
-3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
-*/[0m[32;1m[1;3m
-I found out that the correct column name is 'BillingCountry'. I will now rewrite my query and run it again.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT BillingCountry AS country, COUNT(*) AS invoice_count FROM Invoice GROUP BY BillingCountry ORDER BY invoice_count DESC'}}
-[0m[36;1m[1;3m[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)][0m[32;1m[1;3mRelevant Documents: 1,3,4
-Cited Documents: 4
-Answer: The countries with the most invoices are the USA (91), Canada (56), and France (35).
-Grounded answer: The countries with the most invoices are the USA (91), Canada (56), and France (35).[0m
-
-[1m> Finished chain.[0m
-```
+llm = ChatCohere(model=MODEL, temperature=0.1,verbose=True)
+db = SQLDatabase.from_uri(f"sqlite:///{DB_NAME}")
-```python PYTHON
-print(output['output'])
-```
-```txt title="Output"
-The countries with the most invoices are the USA (91), Canada (56), and France (35).
+toolkit = SQLDatabaseToolkit(db=db, llm=llm)
+context = toolkit.get_context()
+tools = toolkit.get_tools()
+
+print('**List of pre-defined Langchain Tools**')
+print([tool.name for tool in tools])
+print('')
+print('**Context to pass to LLM on tables**')
+print(context)
```
-The agent initially makes some errors as it jumps to answer the question using the db_query tool, but it then realizes it needs to figure out what tables it has access to and what they look like. It then fixes the SQL code and is able to generate the right answer.
+ **List of pre-defined Langchain Tools**
+ ['sql_db_query', 'sql_db_schema', 'sql_db_list_tables', 'sql_db_query_checker']
+
+ **Context to pass to LLM on tables**
+ {'table_info': '\nCREATE TABLE "Album" (\n\t"AlbumId" INTEGER NOT NULL, \n\t"Title" NVARCHAR(160) NOT NULL, \n\t"ArtistId" INTEGER NOT NULL, \n\tPRIMARY KEY ("AlbumId"), \n\tFOREIGN KEY("ArtistId") REFERENCES "Artist" ("ArtistId")\n)\n\n/*\n3 rows from Album table:\nAlbumId\tTitle\tArtistId\n1\tFor Those About To Rock We Salute You\t1\n2\tBalls to the Wall\t2\n3\tRestless and Wild\t2\n*/\n\n\nCREATE TABLE "Artist" (\n\t"ArtistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("ArtistId")\n)\n\n/*\n3 rows from Artist table:\nArtistId\tName\n1\tAC/DC\n2\tAccept\n3\tAerosmith\n*/\n\n\nCREATE TABLE "Customer" (\n\t"CustomerId" INTEGER NOT NULL, \n\t"FirstName" NVARCHAR(40) NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"Company" NVARCHAR(80), \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60) NOT NULL, \n\t"SupportRepId" INTEGER, \n\tPRIMARY KEY ("CustomerId"), \n\tFOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Customer table:\nCustomerId\tFirstName\tLastName\tCompany\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\tSupportRepId\n1\tLuís\tGonçalves\tEmbraer - Empresa Brasileira de Aeronáutica S.A.\tAv. Brigadeiro Faria Lima, 2170\tSão José dos Campos\tSP\tBrazil\t12227-000\t+55 (12) 3923-5555\t+55 (12) 3923-5566\tluisg@embraer.com.br\t3\n2\tLeonie\tKöhler\tNone\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t+49 0711 2842222\tNone\tleonekohler@surfeu.de\t5\n3\tFrançois\tTremblay\tNone\t1498 rue Bélanger\tMontréal\tQC\tCanada\tH2G 1A7\t+1 (514) 721-4711\tNone\tftremblay@gmail.com\t3\n*/\n\n\nCREATE TABLE "Employee" (\n\t"EmployeeId" INTEGER NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"FirstName" NVARCHAR(20) NOT NULL, \n\t"Title" NVARCHAR(30), \n\t"ReportsTo" INTEGER, \n\t"BirthDate" DATETIME, \n\t"HireDate" DATETIME, \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60), \n\tPRIMARY KEY ("EmployeeId"), \n\tFOREIGN KEY("ReportsTo") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Employee table:\nEmployeeId\tLastName\tFirstName\tTitle\tReportsTo\tBirthDate\tHireDate\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\n1\tAdams\tAndrew\tGeneral Manager\tNone\t1962-02-18 00:00:00\t2002-08-14 00:00:00\t11120 Jasper Ave NW\tEdmonton\tAB\tCanada\tT5K 2N1\t+1 (780) 428-9482\t+1 (780) 428-3457\tandrew@chinookcorp.com\n2\tEdwards\tNancy\tSales Manager\t1\t1958-12-08 00:00:00\t2002-05-01 00:00:00\t825 8 Ave SW\tCalgary\tAB\tCanada\tT2P 2T3\t+1 (403) 262-3443\t+1 (403) 262-3322\tnancy@chinookcorp.com\n3\tPeacock\tJane\tSales Support Agent\t2\t1973-08-29 00:00:00\t2002-04-01 00:00:00\t1111 6 Ave SW\tCalgary\tAB\tCanada\tT2P 5M5\t+1 (403) 262-3443\t+1 (403) 262-6712\tjane@chinookcorp.com\n*/\n\n\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Invoice" (\n\t"InvoiceId" INTEGER NOT NULL, \n\t"CustomerId" INTEGER NOT NULL, \n\t"InvoiceDate" DATETIME NOT NULL, \n\t"BillingAddress" NVARCHAR(70), \n\t"BillingCity" NVARCHAR(40), \n\t"BillingState" NVARCHAR(40), \n\t"BillingCountry" NVARCHAR(40), \n\t"BillingPostalCode" NVARCHAR(10), \n\t"Total" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("InvoiceId"), \n\tFOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")\n)\n\n/*\n3 rows from Invoice table:\nInvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n1\t2\t2021-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n2\t4\t2021-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n3\t8\t2021-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n*/\n\n\nCREATE TABLE "InvoiceLine" (\n\t"InvoiceLineId" INTEGER NOT NULL, \n\t"InvoiceId" INTEGER NOT NULL, \n\t"TrackId" INTEGER NOT NULL, \n\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \n\t"Quantity" INTEGER NOT NULL, \n\tPRIMARY KEY ("InvoiceLineId"), \n\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \n\tFOREIGN KEY("InvoiceId") REFERENCES "Invoice" ("InvoiceId")\n)\n\n/*\n3 rows from InvoiceLine table:\nInvoiceLineId\tInvoiceId\tTrackId\tUnitPrice\tQuantity\n1\t1\t2\t0.99\t1\n2\t1\t4\t0.99\t1\n3\t2\t6\t0.99\t1\n*/\n\n\nCREATE TABLE "MediaType" (\n\t"MediaTypeId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("MediaTypeId")\n)\n\n/*\n3 rows from MediaType table:\nMediaTypeId\tName\n1\tMPEG audio file\n2\tProtected AAC audio file\n3\tProtected MPEG-4 video file\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/\n\n\nCREATE TABLE "PlaylistTrack" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"TrackId" INTEGER NOT NULL, \n\tPRIMARY KEY ("PlaylistId", "TrackId"), \n\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \n\tFOREIGN KEY("PlaylistId") REFERENCES "Playlist" ("PlaylistId")\n)\n\n/*\n3 rows from PlaylistTrack table:\nPlaylistId\tTrackId\n1\t3402\n1\t3389\n1\t3390\n*/\n\n\nCREATE TABLE "Track" (\n\t"TrackId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(200) NOT NULL, \n\t"AlbumId" INTEGER, \n\t"MediaTypeId" INTEGER NOT NULL, \n\t"GenreId" INTEGER, \n\t"Composer" NVARCHAR(220), \n\t"Milliseconds" INTEGER NOT NULL, \n\t"Bytes" INTEGER, \n\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("TrackId"), \n\tFOREIGN KEY("MediaTypeId") REFERENCES "MediaType" ("MediaTypeId"), \n\tFOREIGN KEY("GenreId") REFERENCES "Genre" ("GenreId"), \n\tFOREIGN KEY("AlbumId") REFERENCES "Album" ("AlbumId")\n)\n\n/*\n3 rows from Track table:\nTrackId\tName\tAlbumId\tMediaTypeId\tGenreId\tComposer\tMilliseconds\tBytes\tUnitPrice\n1\tFor Those About To Rock (We Salute You)\t1\t1\t1\tAngus Young, Malcolm Young, Brian Johnson\t343719\t11170334\t0.99\n2\tBalls to the Wall\t2\t2\t1\tU. Dirkschneider, W. Hoffmann, H. Frank, P. Baltes, S. Kaufmann, G. Hoffmann\t342562\t5510424\t0.99\n3\tFast As a Shark\t3\t2\t1\tF. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman\t230619\t3990994\t0.99\n*/', 'table_names': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}
-```python PYTHON
-output=agent_executor.invoke({
- "input": 'who is the best customer? The customer who has spent the most money is the best.',
-})
-```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will run a SQL query to find the customer who has spent the most money.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT customer_name, SUM(total_cost) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;'}}
-[0m[36;1m[1;3mError: (sqlite3.OperationalError) no such table: orders
-[SQL: SELECT customer_name, SUM(total_cost) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;]
-(Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
-I received an error message saying that there is no table called 'orders'. I will now use the sql_db_list_tables tool to find out what tables are available.
-{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
-[0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3m
-I found that there is a table called 'Customer'. I will now use the sql_db_schema tool to find out what columns are in the 'Customer' table.
-{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Customer'}}
-[0m[33;1m[1;3m
-CREATE TABLE "Customer" (
- "CustomerId" INTEGER NOT NULL,
- "FirstName" NVARCHAR(40) NOT NULL,
- "LastName" NVARCHAR(20) NOT NULL,
- "Company" NVARCHAR(80),
- "Address" NVARCHAR(70),
- "City" NVARCHAR(40),
- "State" NVARCHAR(40),
- "Country" NVARCHAR(40),
- "PostalCode" NVARCHAR(10),
- "Phone" NVARCHAR(24),
- "Fax" NVARCHAR(24),
- "Email" NVARCHAR(60) NOT NULL,
- "SupportRepId" INTEGER,
- PRIMARY KEY ("CustomerId"),
- FOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")
-)
+
+## SQL Agent
-/*
-3 rows from Customer table:
-CustomerId FirstName LastName Company Address City State Country PostalCode Phone Fax Email SupportRepId
-1 Luís Gonçalves Embraer - Empresa Brasileira de Aeronáutica S.A. Av. Brigadeiro Faria Lima, 2170 São José dos Campos SP Brazil 12227-000 +55 (12) 3923-5555 +55 (12) 3923-5566 luisg@embraer.com.br 3
-2 Leonie Köhler None Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 +49 0711 2842222 None leonekohler@surfeu.de 5
-3 François Tremblay None 1498 rue Bélanger Montréal QC Canada H2G 1A7 +1 (514) 721-4711 None ftremblay@gmail.com 3
-*/[0m[32;1m[1;3m
-I found that the 'Customer' table does not contain any information about how much money a customer has spent. I will now use the sql_db_schema tool to find out what columns are in the 'Invoice' table.
-{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Invoice'}}
-[0m[33;1m[1;3m
-CREATE TABLE "Invoice" (
- "InvoiceId" INTEGER NOT NULL,
- "CustomerId" INTEGER NOT NULL,
- "InvoiceDate" DATETIME NOT NULL,
- "BillingAddress" NVARCHAR(70),
- "BillingCity" NVARCHAR(40),
- "BillingState" NVARCHAR(40),
- "BillingCountry" NVARCHAR(40),
- "BillingPostalCode" NVARCHAR(10),
- "Total" NUMERIC(10, 2) NOT NULL,
- PRIMARY KEY ("InvoiceId"),
- FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
-)
+we follow the general cohere react agent setup in Langchain to build our SQL agent.
-/*
-3 rows from Invoice table:
-InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
-1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
-2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
-3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
-*/[0m[32;1m[1;3m
-I found that the 'Invoice' table contains a 'Total' column, which is likely to be the total amount spent by the customer on that invoice. I will now use the sql_db_query tool to find the customer who has spent the most money.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS total_spent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY total_spent DESC LIMIT 1;'}}
-[0m[36;1m[1;3m[('Helena', 'Holý', 49.62)][0m[32;1m[1;3mRelevant Documents: 1,2,3,4
-Cited Documents: 4
-Answer: The best customer is Helena Holý, who has spent a total of 49.62.
-Grounded answer: The best customer is Helena Holý, who has spent a total of 49.62.[0m
-
-[1m> Finished chain.[0m
-```
-```python PYTHON
-print(output['output'])
-```
+```python
-```txt title="Output"
-The best customer is Helena Holý, who has spent a total of 49.62.
-```
+# define the prompt template
+prompt = ChatPromptTemplate.from_template("{input}")
-As you can see, the agent makes an error, but is able to rectify itself. It also manages to generate a SQL query over two tables in the database.
+# instantiate the ReAct agent
+agent = create_cohere_react_agent(
+ llm=llm,
+ tools=tools,
+ prompt=prompt,
+)
+agent_executor = AgentExecutor(agent=agent,
+ tools=tools,
+ verbose=True,
+ return_intermediate_steps=True
+ )
-# SQL Agent with context [#sec_step2]
-Generally, passing in additional context to the preamble can help reduce the initial failures. This context is provided by the SQLDBToolkit and contains the first 3 rows of the tables in the Database.
+```
-```python PYTHON
-print('**Context to pass to LLM on tables**')
-print('Table Names')
-print(context['table_names'])
-print('Table Schemas')
-print(context['table_info'])
+
+```python
+agent_executor.invoke({
+ "input": 'what tables are available?',
+})
```
-```sql title="Output"
-**Context to pass to LLM on tables**
-Table Names
-Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track
-Table Schemas
-
-CREATE TABLE "Album" (
- "AlbumId" INTEGER NOT NULL,
- "Title" NVARCHAR(160) NOT NULL,
- "ArtistId" INTEGER NOT NULL,
- PRIMARY KEY ("AlbumId"),
- FOREIGN KEY("ArtistId") REFERENCES "Artist" ("ArtistId")
-)
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use the sql_db_list_tables tool to find out what tables are available.
+ {'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
+ [0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.
+ Grounded answer: The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.[0m
+
+ [1m> Finished chain.[0m
-/*
-3 rows from Album table:
-AlbumId Title ArtistId
-1 For Those About To Rock We Salute You 1
-2 Balls to the Wall 2
-3 Restless and Wild 2
-*/
-CREATE TABLE "Artist" (
- "ArtistId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("ArtistId")
-)
-/*
-3 rows from Artist table:
-ArtistId Name
-1 AC/DC
-2 Accept
-3 Aerosmith
-*/
-
-
-CREATE TABLE "Customer" (
- "CustomerId" INTEGER NOT NULL,
- "FirstName" NVARCHAR(40) NOT NULL,
- "LastName" NVARCHAR(20) NOT NULL,
- "Company" NVARCHAR(80),
- "Address" NVARCHAR(70),
- "City" NVARCHAR(40),
- "State" NVARCHAR(40),
- "Country" NVARCHAR(40),
- "PostalCode" NVARCHAR(10),
- "Phone" NVARCHAR(24),
- "Fax" NVARCHAR(24),
- "Email" NVARCHAR(60) NOT NULL,
- "SupportRepId" INTEGER,
- PRIMARY KEY ("CustomerId"),
- FOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")
-)
-/*
-3 rows from Customer table:
-CustomerId FirstName LastName Company Address City State Country PostalCode Phone Fax Email SupportRepId
-1 Luís Gonçalves Embraer - Empresa Brasileira de Aeronáutica S.A. Av. Brigadeiro Faria Lima, 2170 São José dos Campos SP Brazil 12227-000 +55 (12) 3923-5555 +55 (12) 3923-5566 luisg@embraer.com.br 3
-2 Leonie Köhler None Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 +49 0711 2842222 None leonekohler@surfeu.de 5
-3 François Tremblay None 1498 rue Bélanger Montréal QC Canada H2G 1A7 +1 (514) 721-4711 None ftremblay@gmail.com 3
-*/
-
-
-CREATE TABLE "Employee" (
- "EmployeeId" INTEGER NOT NULL,
- "LastName" NVARCHAR(20) NOT NULL,
- "FirstName" NVARCHAR(20) NOT NULL,
- "Title" NVARCHAR(30),
- "ReportsTo" INTEGER,
- "BirthDate" DATETIME,
- "HireDate" DATETIME,
- "Address" NVARCHAR(70),
- "City" NVARCHAR(40),
- "State" NVARCHAR(40),
- "Country" NVARCHAR(40),
- "PostalCode" NVARCHAR(10),
- "Phone" NVARCHAR(24),
- "Fax" NVARCHAR(24),
- "Email" NVARCHAR(60),
- PRIMARY KEY ("EmployeeId"),
- FOREIGN KEY("ReportsTo") REFERENCES "Employee" ("EmployeeId")
-)
+ {'input': 'what tables are available?',
+ 'output': 'The following tables are available: Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track.',
+ 'citations': [CohereCitation(start=36, end=41, text='Album', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=43, end=49, text='Artist', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=51, end=59, text='Customer', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=61, end=69, text='Employee', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=71, end=76, text='Genre', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=78, end=85, text='Invoice', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=87, end=98, text='InvoiceLine', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=100, end=109, text='MediaType', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=111, end=119, text='Playlist', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=121, end=134, text='PlaylistTrack', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}]),
+ CohereCitation(start=136, end=141, text='Track', documents=[{'output': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='sql_db_list_tables', tool_input={'tool_input': ''}, log="\nI will use the sql_db_list_tables tool to find out what tables are available.\n{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}\n", message_log=[AIMessage(content='\nPlan: I will use the sql_db_list_tables tool to find out what tables are available.\nAction: ```json\n[\n {\n "tool_name": "sql_db_list_tables",\n "parameters": {\n "tool_input": ""\n }\n }\n]\n```')]),
+ 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track')]}
-/*
-3 rows from Employee table:
-EmployeeId LastName FirstName Title ReportsTo BirthDate HireDate Address City State Country PostalCode Phone Fax Email
-1 Adams Andrew General Manager None 1962-02-18 00:00:00 2002-08-14 00:00:00 11120 Jasper Ave NW Edmonton AB Canada T5K 2N1 +1 (780) 428-9482 +1 (780) 428-3457 andrew@chinookcorp.com
-2 Edwards Nancy Sales Manager 1 1958-12-08 00:00:00 2002-05-01 00:00:00 825 8 Ave SW Calgary AB Canada T2P 2T3 +1 (403) 262-3443 +1 (403) 262-3322 nancy@chinookcorp.com
-3 Peacock Jane Sales Support Agent 2 1973-08-29 00:00:00 2002-04-01 00:00:00 1111 6 Ave SW Calgary AB Canada T2P 5M5 +1 (403) 262-3443 +1 (403) 262-6712 jane@chinookcorp.com
-*/
-CREATE TABLE "Genre" (
- "GenreId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("GenreId")
-)
+The agent uses the list_tables tool to effectively highlight all the tables in the DB
-/*
-3 rows from Genre table:
-GenreId Name
-1 Rock
-2 Jazz
-3 Metal
-*/
-
-
-CREATE TABLE "Invoice" (
- "InvoiceId" INTEGER NOT NULL,
- "CustomerId" INTEGER NOT NULL,
- "InvoiceDate" DATETIME NOT NULL,
- "BillingAddress" NVARCHAR(70),
- "BillingCity" NVARCHAR(40),
- "BillingState" NVARCHAR(40),
- "BillingCountry" NVARCHAR(40),
- "BillingPostalCode" NVARCHAR(10),
- "Total" NUMERIC(10, 2) NOT NULL,
- PRIMARY KEY ("InvoiceId"),
- FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
-)
-/*
-3 rows from Invoice table:
-InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
-1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
-2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
-3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
-*/
-
-
-CREATE TABLE "InvoiceLine" (
- "InvoiceLineId" INTEGER NOT NULL,
- "InvoiceId" INTEGER NOT NULL,
- "TrackId" INTEGER NOT NULL,
- "UnitPrice" NUMERIC(10, 2) NOT NULL,
- "Quantity" INTEGER NOT NULL,
- PRIMARY KEY ("InvoiceLineId"),
- FOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"),
- FOREIGN KEY("InvoiceId") REFERENCES "Invoice" ("InvoiceId")
-)
+```python
+agent_executor.invoke({
+ "input": 'show the first row of the Playlist and Genre tables?',
+})
+```
-/*
-3 rows from InvoiceLine table:
-InvoiceLineId InvoiceId TrackId UnitPrice Quantity
-1 1 2 0.99 1
-2 1 4 0.99 1
-3 2 6 0.99 1
-*/
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will use the sql_db_schema tool to find the first row of the Playlist and Genre tables.
+ {'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Playlist, Genre'}}
+ [0m[33;1m[1;3m
+ CREATE TABLE "Genre" (
+ "GenreId" INTEGER NOT NULL,
+ "Name" NVARCHAR(120),
+ PRIMARY KEY ("GenreId")
+ )
+
+ /*
+ 3 rows from Genre table:
+ GenreId Name
+ 1 Rock
+ 2 Jazz
+ 3 Metal
+ */
+
+
+ CREATE TABLE "Playlist" (
+ "PlaylistId" INTEGER NOT NULL,
+ "Name" NVARCHAR(120),
+ PRIMARY KEY ("PlaylistId")
+ )
+
+ /*
+ 3 rows from Playlist table:
+ PlaylistId Name
+ 1 Music
+ 2 Movies
+ 3 TV Shows
+ */[0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: Here is the first row of the Genre table:
+
+ | GenreId | Name |
+ | --- | --- |
+ | 1 | Rock |
+
+ Here is the first row of the Playlist table:
+
+ | PlaylistId | Name |
+ | --- | --- |
+ | 1 | Music |
+ Grounded answer: Here is the first row of the Genre table:
+
+ | GenreId | Name |
+ | --- | --- |
+ | 1 | Rock |
+
+ Here is the first row of the Playlist table:
+
+ | PlaylistId | Name |
+ | --- | --- |
+ | 1 | Music |[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ {'input': 'show the first row of the Playlist and Genre tables?',
+ 'output': 'Here is the first row of the Genre table:\n\n| GenreId | Name |\n| --- | --- |\n| 1 | Rock |\n\nHere is the first row of the Playlist table:\n\n| PlaylistId | Name |\n| --- | --- |\n| 1 | Music |',
+ 'citations': [CohereCitation(start=45, end=52, text='GenreId', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=55, end=59, text='Name', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=78, end=79, text='1', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=82, end=86, text='Rock', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=138, end=148, text='PlaylistId', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=151, end=155, text='Name', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=174, end=175, text='1', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}]),
+ CohereCitation(start=178, end=183, text='Music', documents=[{'output': '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/'}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='sql_db_schema', tool_input={'table_names': 'Playlist, Genre'}, log="\nI will use the sql_db_schema tool to find the first row of the Playlist and Genre tables.\n{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Playlist, Genre'}}\n", message_log=[AIMessage(content='\nPlan: I will use the sql_db_schema tool to find the first row of the Playlist and Genre tables.\nAction: ```json\n[\n {\n "tool_name": "sql_db_schema",\n "parameters": {\n "table_names": "Playlist, Genre"\n }\n }\n]\n```')]),
+ '\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/')]}
+
+
+
+Here we see that the tool takes a list of tables to query the sql_db_schema tool to retrieve the various schemas
+
+
+```python
+agent_executor.invoke({
+ "input": 'which countries have the most invoices?',
+})
+```
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for the number of invoices per country and then write an answer based on the results.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC'}}
+ [0m[36;1m[1;3mError: (sqlite3.OperationalError) no such table: invoices
+ [SQL: SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC]
+ (Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
+ I received an error message. I will now use the sql_db_list_tables tool to find out the name of the table containing the invoices data.
+ {'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
+ [0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3m
+ I found out that the table name is 'Invoice'. I will now rewrite my query and run it again.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}}
+ [0m[36;1m[1;3mError: (sqlite3.OperationalError) no such column: country
+ [SQL: SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC]
+ (Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
+ I received another error message. I will now use the sql_db_schema tool to find out the column names in the 'Invoice' table.
+ {'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Invoice'}}
+ [0m[33;1m[1;3m
+ CREATE TABLE "Invoice" (
+ "InvoiceId" INTEGER NOT NULL,
+ "CustomerId" INTEGER NOT NULL,
+ "InvoiceDate" DATETIME NOT NULL,
+ "BillingAddress" NVARCHAR(70),
+ "BillingCity" NVARCHAR(40),
+ "BillingState" NVARCHAR(40),
+ "BillingCountry" NVARCHAR(40),
+ "BillingPostalCode" NVARCHAR(10),
+ "Total" NUMERIC(10, 2) NOT NULL,
+ PRIMARY KEY ("InvoiceId"),
+ FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
+ )
+
+ /*
+ 3 rows from Invoice table:
+ InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
+ 1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
+ 2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
+ 3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
+ */[0m[32;1m[1;3m
+ I found out that the column name for country is 'BillingCountry'. I will now rewrite my query and run it again.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT BillingCountry AS country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}}
+ [0m[36;1m[1;3m[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)][0m[32;1m[1;3mRelevant Documents: 1,3,4
+ Cited Documents: 4
+ Answer: The countries with the most invoices are the USA (91), Canada (56), and France (35).
+ Grounded answer: The countries with the most invoices are the USA (91), Canada (56), and France (35).[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ {'input': 'which countries have the most invoices?',
+ 'output': 'The countries with the most invoices are the USA (91), Canada (56), and France (35).',
+ 'citations': [CohereCitation(start=45, end=52, text='USA (91', documents=[{'output': "[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)]"}]),
+ CohereCitation(start=55, end=65, text='Canada (56', documents=[{'output': "[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)]"}]),
+ CohereCitation(start=72, end=82, text='France (35', documents=[{'output': "[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)]"}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC'}, log="\nI will search for the number of invoices per country and then write an answer based on the results.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC'}}\n", message_log=[AIMessage(content='\nPlan: I will search for the number of invoices per country and then write an answer based on the results.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC"\n }\n }\n]\n```')]),
+ 'Error: (sqlite3.OperationalError) no such table: invoices\n[SQL: SELECT country, COUNT(*) AS invoice_count FROM invoices GROUP BY country ORDER BY invoice_count DESC]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)'),
+ (AgentActionMessageLog(tool='sql_db_list_tables', tool_input={'tool_input': ''}, log="\nI received an error message. I will now use the sql_db_list_tables tool to find out the name of the table containing the invoices data.\n{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}\n", message_log=[AIMessage(content='\nReflection: I received an error message. I will now use the sql_db_list_tables tool to find out the name of the table containing the invoices data.\nAction: ```json\n[\n {\n "tool_name": "sql_db_list_tables",\n "parameters": {\n "tool_input": ""\n }\n }\n]\n```')]),
+ 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'),
+ (AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}, log="\nI found out that the table name is 'Invoice'. I will now rewrite my query and run it again.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}}\n", message_log=[AIMessage(content='\nReflection: I found out that the table name is \'Invoice\'. I will now rewrite my query and run it again.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC"\n }\n }\n]\n```')]),
+ 'Error: (sqlite3.OperationalError) no such column: country\n[SQL: SELECT country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)'),
+ (AgentActionMessageLog(tool='sql_db_schema', tool_input={'table_names': 'Invoice'}, log="\nI received another error message. I will now use the sql_db_schema tool to find out the column names in the 'Invoice' table.\n{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Invoice'}}\n", message_log=[AIMessage(content='\nReflection: I received another error message. I will now use the sql_db_schema tool to find out the column names in the \'Invoice\' table.\nAction: ```json\n[\n {\n "tool_name": "sql_db_schema",\n "parameters": {\n "table_names": "Invoice"\n }\n }\n]\n```')]),
+ '\nCREATE TABLE "Invoice" (\n\t"InvoiceId" INTEGER NOT NULL, \n\t"CustomerId" INTEGER NOT NULL, \n\t"InvoiceDate" DATETIME NOT NULL, \n\t"BillingAddress" NVARCHAR(70), \n\t"BillingCity" NVARCHAR(40), \n\t"BillingState" NVARCHAR(40), \n\t"BillingCountry" NVARCHAR(40), \n\t"BillingPostalCode" NVARCHAR(10), \n\t"Total" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("InvoiceId"), \n\tFOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")\n)\n\n/*\n3 rows from Invoice table:\nInvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n1\t2\t2021-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n2\t4\t2021-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n3\t8\t2021-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n*/'),
+ (AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT BillingCountry AS country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}, log="\nI found out that the column name for country is 'BillingCountry'. I will now rewrite my query and run it again.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT BillingCountry AS country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC'}}\n", message_log=[AIMessage(content='\nReflection: I found out that the column name for country is \'BillingCountry\'. I will now rewrite my query and run it again.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT BillingCountry AS country, COUNT(*) AS invoice_count FROM Invoice GROUP BY country ORDER BY invoice_count DESC"\n }\n }\n]\n```')]),
+ "[('USA', 91), ('Canada', 56), ('France', 35), ('Brazil', 35), ('Germany', 28), ('United Kingdom', 21), ('Portugal', 14), ('Czech Republic', 14), ('India', 13), ('Sweden', 7), ('Spain', 7), ('Poland', 7), ('Norway', 7), ('Netherlands', 7), ('Italy', 7), ('Ireland', 7), ('Hungary', 7), ('Finland', 7), ('Denmark', 7), ('Chile', 7), ('Belgium', 7), ('Austria', 7), ('Australia', 7), ('Argentina', 7)]")]}
+
+
+
+The agent initially makes some errors as it jumps to answer the question using the db_query tool, but it then realizes it needs to figure out what tables it has access to and what they look like. It then fixes the sql code and is able to generate the right answer
+
+
+```python
+agent_executor.invoke({
+ "input": 'who is the best customer? The customer who has spent the most money is the best.',
+})
+```
-CREATE TABLE "MediaType" (
- "MediaTypeId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("MediaTypeId")
-)
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will search for the customer who has spent the most money and write an answer based on the results.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;'}}
+ [0m[36;1m[1;3mError: (sqlite3.OperationalError) no such table: orders
+ [SQL: SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;]
+ (Background on this error at: https://sqlalche.me/e/20/e3q8)[0m[32;1m[1;3m
+ I received an error message. I will now use the sql_db_list_tables tool to find out which tables are available.
+ {'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}
+ [0m[38;5;200m[1;3mAlbum, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track[0m[32;1m[1;3m
+ I found that there is a 'Customer' table and an 'Invoice' table. I will now use the sql_db_schema tool to find out more about these tables.
+ {'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Customer,Invoice'}}
+ [0m[33;1m[1;3m
+ CREATE TABLE "Customer" (
+ "CustomerId" INTEGER NOT NULL,
+ "FirstName" NVARCHAR(40) NOT NULL,
+ "LastName" NVARCHAR(20) NOT NULL,
+ "Company" NVARCHAR(80),
+ "Address" NVARCHAR(70),
+ "City" NVARCHAR(40),
+ "State" NVARCHAR(40),
+ "Country" NVARCHAR(40),
+ "PostalCode" NVARCHAR(10),
+ "Phone" NVARCHAR(24),
+ "Fax" NVARCHAR(24),
+ "Email" NVARCHAR(60) NOT NULL,
+ "SupportRepId" INTEGER,
+ PRIMARY KEY ("CustomerId"),
+ FOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")
+ )
+
+ /*
+ 3 rows from Customer table:
+ CustomerId FirstName LastName Company Address City State Country PostalCode Phone Fax Email SupportRepId
+ 1 Luís Gonçalves Embraer - Empresa Brasileira de Aeronáutica S.A. Av. Brigadeiro Faria Lima, 2170 São José dos Campos SP Brazil 12227-000 +55 (12) 3923-5555 +55 (12) 3923-5566 luisg@embraer.com.br 3
+ 2 Leonie Köhler None Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 +49 0711 2842222 None leonekohler@surfeu.de 5
+ 3 François Tremblay None 1498 rue Bélanger Montréal QC Canada H2G 1A7 +1 (514) 721-4711 None ftremblay@gmail.com 3
+ */
+
+
+ CREATE TABLE "Invoice" (
+ "InvoiceId" INTEGER NOT NULL,
+ "CustomerId" INTEGER NOT NULL,
+ "InvoiceDate" DATETIME NOT NULL,
+ "BillingAddress" NVARCHAR(70),
+ "BillingCity" NVARCHAR(40),
+ "BillingState" NVARCHAR(40),
+ "BillingCountry" NVARCHAR(40),
+ "BillingPostalCode" NVARCHAR(10),
+ "Total" NUMERIC(10, 2) NOT NULL,
+ PRIMARY KEY ("InvoiceId"),
+ FOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")
+ )
+
+ /*
+ 3 rows from Invoice table:
+ InvoiceId CustomerId InvoiceDate BillingAddress BillingCity BillingState BillingCountry BillingPostalCode Total
+ 1 2 2021-01-01 00:00:00 Theodor-Heuss-Straße 34 Stuttgart None Germany 70174 1.98
+ 2 4 2021-01-02 00:00:00 Ullevålsveien 14 Oslo None Norway 0171 3.96
+ 3 8 2021-01-03 00:00:00 Grétrystraat 63 Brussels None Belgium 1000 5.94
+ */[0m[32;1m[1;3m
+ I found that the 'Customer' table contains information about customers, including their names, addresses, and phone numbers. The 'Invoice' table contains information about invoices, including the customer ID, invoice date, and total amount. I will now write a new query to find the customer who has spent the most money.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS total_spent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY total_spent DESC LIMIT 1;'}}
+ [0m[36;1m[1;3m[('Helena', 'Holý', 49.62)][0m[32;1m[1;3mRelevant Documents: 1,2,3
+ Cited Documents: 3
+ Answer: The best customer is Helena Holý, who has spent a total of 49.62.
+ Grounded answer: The best customer is Helena Holý, who has spent a total of 49.62.[0m
+
+ [1m> Finished chain.[0m
+
+
+
+
+
+ {'input': 'who is the best customer? The customer who has spent the most money is the best.',
+ 'output': 'The best customer is Helena Holý, who has spent a total of 49.62.',
+ 'citations': [CohereCitation(start=21, end=32, text='Helena Holý', documents=[{'output': "[('Helena', 'Holý', 49.62)]"}]),
+ CohereCitation(start=59, end=64, text='49.62', documents=[{'output': "[('Helena', 'Holý', 49.62)]"}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;'}, log="\nI will search for the customer who has spent the most money and write an answer based on the results.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;'}}\n", message_log=[AIMessage(content='\nPlan: I will search for the customer who has spent the most money and write an answer based on the results.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;"\n }\n }\n]\n```')]),
+ 'Error: (sqlite3.OperationalError) no such table: orders\n[SQL: SELECT customer_name, SUM(total_price) AS total_spent FROM orders GROUP BY customer_name ORDER BY total_spent DESC LIMIT 1;]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)'),
+ (AgentActionMessageLog(tool='sql_db_list_tables', tool_input={'tool_input': ''}, log="\nI received an error message. I will now use the sql_db_list_tables tool to find out which tables are available.\n{'tool_name': 'sql_db_list_tables', 'parameters': {'tool_input': ''}}\n", message_log=[AIMessage(content='\nReflection: I received an error message. I will now use the sql_db_list_tables tool to find out which tables are available.\nAction: ```json\n[\n {\n "tool_name": "sql_db_list_tables",\n "parameters": {\n "tool_input": ""\n }\n }\n]\n```')]),
+ 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'),
+ (AgentActionMessageLog(tool='sql_db_schema', tool_input={'table_names': 'Customer,Invoice'}, log="\nI found that there is a 'Customer' table and an 'Invoice' table. I will now use the sql_db_schema tool to find out more about these tables.\n{'tool_name': 'sql_db_schema', 'parameters': {'table_names': 'Customer,Invoice'}}\n", message_log=[AIMessage(content='\nReflection: I found that there is a \'Customer\' table and an \'Invoice\' table. I will now use the sql_db_schema tool to find out more about these tables.\nAction: ```json\n[\n {\n "tool_name": "sql_db_schema",\n "parameters": {\n "table_names": "Customer,Invoice"\n }\n }\n]\n```')]),
+ '\nCREATE TABLE "Customer" (\n\t"CustomerId" INTEGER NOT NULL, \n\t"FirstName" NVARCHAR(40) NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"Company" NVARCHAR(80), \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60) NOT NULL, \n\t"SupportRepId" INTEGER, \n\tPRIMARY KEY ("CustomerId"), \n\tFOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Customer table:\nCustomerId\tFirstName\tLastName\tCompany\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\tSupportRepId\n1\tLuís\tGonçalves\tEmbraer - Empresa Brasileira de Aeronáutica S.A.\tAv. Brigadeiro Faria Lima, 2170\tSão José dos Campos\tSP\tBrazil\t12227-000\t+55 (12) 3923-5555\t+55 (12) 3923-5566\tluisg@embraer.com.br\t3\n2\tLeonie\tKöhler\tNone\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t+49 0711 2842222\tNone\tleonekohler@surfeu.de\t5\n3\tFrançois\tTremblay\tNone\t1498 rue Bélanger\tMontréal\tQC\tCanada\tH2G 1A7\t+1 (514) 721-4711\tNone\tftremblay@gmail.com\t3\n*/\n\n\nCREATE TABLE "Invoice" (\n\t"InvoiceId" INTEGER NOT NULL, \n\t"CustomerId" INTEGER NOT NULL, \n\t"InvoiceDate" DATETIME NOT NULL, \n\t"BillingAddress" NVARCHAR(70), \n\t"BillingCity" NVARCHAR(40), \n\t"BillingState" NVARCHAR(40), \n\t"BillingCountry" NVARCHAR(40), \n\t"BillingPostalCode" NVARCHAR(10), \n\t"Total" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("InvoiceId"), \n\tFOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")\n)\n\n/*\n3 rows from Invoice table:\nInvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n1\t2\t2021-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n2\t4\t2021-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n3\t8\t2021-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n*/'),
+ (AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS total_spent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY total_spent DESC LIMIT 1;'}, log="\nI found that the 'Customer' table contains information about customers, including their names, addresses, and phone numbers. The 'Invoice' table contains information about invoices, including the customer ID, invoice date, and total amount. I will now write a new query to find the customer who has spent the most money.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS total_spent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY total_spent DESC LIMIT 1;'}}\n", message_log=[AIMessage(content='\nReflection: I found that the \'Customer\' table contains information about customers, including their names, addresses, and phone numbers. The \'Invoice\' table contains information about invoices, including the customer ID, invoice date, and total amount. I will now write a new query to find the customer who has spent the most money.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT c.FirstName, c.LastName, SUM(i.Total) AS total_spent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY total_spent DESC LIMIT 1;"\n }\n }\n]\n```')]),
+ "[('Helena', 'Holý', 49.62)]")]}
+
+
+
+As you can see, the agent makes an error, but is able to rectify itself. It also manages to generate SQL query over two tables in the database
+
+
+## SQL Agent with context
+
+From our experiments, we have found that passing in additional context to the preamble can help reduce the initial failures. This context is provided by the SQLDBToolkit and contains the first 3 rows of the tables in the Database
+
+
+```python
+context
+```
-/*
-3 rows from MediaType table:
-MediaTypeId Name
-1 MPEG audio file
-2 Protected AAC audio file
-3 Protected MPEG-4 video file
-*/
-CREATE TABLE "Playlist" (
- "PlaylistId" INTEGER NOT NULL,
- "Name" NVARCHAR(120),
- PRIMARY KEY ("PlaylistId")
-)
-/*
-3 rows from Playlist table:
-PlaylistId Name
-1 Music
-2 Movies
-3 TV Shows
-*/
-
-
-CREATE TABLE "PlaylistTrack" (
- "PlaylistId" INTEGER NOT NULL,
- "TrackId" INTEGER NOT NULL,
- PRIMARY KEY ("PlaylistId", "TrackId"),
- FOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"),
- FOREIGN KEY("PlaylistId") REFERENCES "Playlist" ("PlaylistId")
-)
+ {'table_info': '\nCREATE TABLE "Album" (\n\t"AlbumId" INTEGER NOT NULL, \n\t"Title" NVARCHAR(160) NOT NULL, \n\t"ArtistId" INTEGER NOT NULL, \n\tPRIMARY KEY ("AlbumId"), \n\tFOREIGN KEY("ArtistId") REFERENCES "Artist" ("ArtistId")\n)\n\n/*\n3 rows from Album table:\nAlbumId\tTitle\tArtistId\n1\tFor Those About To Rock We Salute You\t1\n2\tBalls to the Wall\t2\n3\tRestless and Wild\t2\n*/\n\n\nCREATE TABLE "Artist" (\n\t"ArtistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("ArtistId")\n)\n\n/*\n3 rows from Artist table:\nArtistId\tName\n1\tAC/DC\n2\tAccept\n3\tAerosmith\n*/\n\n\nCREATE TABLE "Customer" (\n\t"CustomerId" INTEGER NOT NULL, \n\t"FirstName" NVARCHAR(40) NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"Company" NVARCHAR(80), \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60) NOT NULL, \n\t"SupportRepId" INTEGER, \n\tPRIMARY KEY ("CustomerId"), \n\tFOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Customer table:\nCustomerId\tFirstName\tLastName\tCompany\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\tSupportRepId\n1\tLuís\tGonçalves\tEmbraer - Empresa Brasileira de Aeronáutica S.A.\tAv. Brigadeiro Faria Lima, 2170\tSão José dos Campos\tSP\tBrazil\t12227-000\t+55 (12) 3923-5555\t+55 (12) 3923-5566\tluisg@embraer.com.br\t3\n2\tLeonie\tKöhler\tNone\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t+49 0711 2842222\tNone\tleonekohler@surfeu.de\t5\n3\tFrançois\tTremblay\tNone\t1498 rue Bélanger\tMontréal\tQC\tCanada\tH2G 1A7\t+1 (514) 721-4711\tNone\tftremblay@gmail.com\t3\n*/\n\n\nCREATE TABLE "Employee" (\n\t"EmployeeId" INTEGER NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"FirstName" NVARCHAR(20) NOT NULL, \n\t"Title" NVARCHAR(30), \n\t"ReportsTo" INTEGER, \n\t"BirthDate" DATETIME, \n\t"HireDate" DATETIME, \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60), \n\tPRIMARY KEY ("EmployeeId"), \n\tFOREIGN KEY("ReportsTo") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Employee table:\nEmployeeId\tLastName\tFirstName\tTitle\tReportsTo\tBirthDate\tHireDate\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\n1\tAdams\tAndrew\tGeneral Manager\tNone\t1962-02-18 00:00:00\t2002-08-14 00:00:00\t11120 Jasper Ave NW\tEdmonton\tAB\tCanada\tT5K 2N1\t+1 (780) 428-9482\t+1 (780) 428-3457\tandrew@chinookcorp.com\n2\tEdwards\tNancy\tSales Manager\t1\t1958-12-08 00:00:00\t2002-05-01 00:00:00\t825 8 Ave SW\tCalgary\tAB\tCanada\tT2P 2T3\t+1 (403) 262-3443\t+1 (403) 262-3322\tnancy@chinookcorp.com\n3\tPeacock\tJane\tSales Support Agent\t2\t1973-08-29 00:00:00\t2002-04-01 00:00:00\t1111 6 Ave SW\tCalgary\tAB\tCanada\tT2P 5M5\t+1 (403) 262-3443\t+1 (403) 262-6712\tjane@chinookcorp.com\n*/\n\n\nCREATE TABLE "Genre" (\n\t"GenreId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("GenreId")\n)\n\n/*\n3 rows from Genre table:\nGenreId\tName\n1\tRock\n2\tJazz\n3\tMetal\n*/\n\n\nCREATE TABLE "Invoice" (\n\t"InvoiceId" INTEGER NOT NULL, \n\t"CustomerId" INTEGER NOT NULL, \n\t"InvoiceDate" DATETIME NOT NULL, \n\t"BillingAddress" NVARCHAR(70), \n\t"BillingCity" NVARCHAR(40), \n\t"BillingState" NVARCHAR(40), \n\t"BillingCountry" NVARCHAR(40), \n\t"BillingPostalCode" NVARCHAR(10), \n\t"Total" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("InvoiceId"), \n\tFOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")\n)\n\n/*\n3 rows from Invoice table:\nInvoiceId\tCustomerId\tInvoiceDate\tBillingAddress\tBillingCity\tBillingState\tBillingCountry\tBillingPostalCode\tTotal\n1\t2\t2021-01-01 00:00:00\tTheodor-Heuss-Straße 34\tStuttgart\tNone\tGermany\t70174\t1.98\n2\t4\t2021-01-02 00:00:00\tUllevålsveien 14\tOslo\tNone\tNorway\t0171\t3.96\n3\t8\t2021-01-03 00:00:00\tGrétrystraat 63\tBrussels\tNone\tBelgium\t1000\t5.94\n*/\n\n\nCREATE TABLE "InvoiceLine" (\n\t"InvoiceLineId" INTEGER NOT NULL, \n\t"InvoiceId" INTEGER NOT NULL, \n\t"TrackId" INTEGER NOT NULL, \n\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \n\t"Quantity" INTEGER NOT NULL, \n\tPRIMARY KEY ("InvoiceLineId"), \n\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \n\tFOREIGN KEY("InvoiceId") REFERENCES "Invoice" ("InvoiceId")\n)\n\n/*\n3 rows from InvoiceLine table:\nInvoiceLineId\tInvoiceId\tTrackId\tUnitPrice\tQuantity\n1\t1\t2\t0.99\t1\n2\t1\t4\t0.99\t1\n3\t2\t6\t0.99\t1\n*/\n\n\nCREATE TABLE "MediaType" (\n\t"MediaTypeId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("MediaTypeId")\n)\n\n/*\n3 rows from MediaType table:\nMediaTypeId\tName\n1\tMPEG audio file\n2\tProtected AAC audio file\n3\tProtected MPEG-4 video file\n*/\n\n\nCREATE TABLE "Playlist" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(120), \n\tPRIMARY KEY ("PlaylistId")\n)\n\n/*\n3 rows from Playlist table:\nPlaylistId\tName\n1\tMusic\n2\tMovies\n3\tTV Shows\n*/\n\n\nCREATE TABLE "PlaylistTrack" (\n\t"PlaylistId" INTEGER NOT NULL, \n\t"TrackId" INTEGER NOT NULL, \n\tPRIMARY KEY ("PlaylistId", "TrackId"), \n\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \n\tFOREIGN KEY("PlaylistId") REFERENCES "Playlist" ("PlaylistId")\n)\n\n/*\n3 rows from PlaylistTrack table:\nPlaylistId\tTrackId\n1\t3402\n1\t3389\n1\t3390\n*/\n\n\nCREATE TABLE "Track" (\n\t"TrackId" INTEGER NOT NULL, \n\t"Name" NVARCHAR(200) NOT NULL, \n\t"AlbumId" INTEGER, \n\t"MediaTypeId" INTEGER NOT NULL, \n\t"GenreId" INTEGER, \n\t"Composer" NVARCHAR(220), \n\t"Milliseconds" INTEGER NOT NULL, \n\t"Bytes" INTEGER, \n\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \n\tPRIMARY KEY ("TrackId"), \n\tFOREIGN KEY("MediaTypeId") REFERENCES "MediaType" ("MediaTypeId"), \n\tFOREIGN KEY("GenreId") REFERENCES "Genre" ("GenreId"), \n\tFOREIGN KEY("AlbumId") REFERENCES "Album" ("AlbumId")\n)\n\n/*\n3 rows from Track table:\nTrackId\tName\tAlbumId\tMediaTypeId\tGenreId\tComposer\tMilliseconds\tBytes\tUnitPrice\n1\tFor Those About To Rock (We Salute You)\t1\t1\t1\tAngus Young, Malcolm Young, Brian Johnson\t343719\t11170334\t0.99\n2\tBalls to the Wall\t2\t2\t1\tU. Dirkschneider, W. Hoffmann, H. Frank, P. Baltes, S. Kaufmann, G. Hoffmann\t342562\t5510424\t0.99\n3\tFast As a Shark\t3\t2\t1\tF. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman\t230619\t3990994\t0.99\n*/',
+ 'table_names': 'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track'}
-/*
-3 rows from PlaylistTrack table:
-PlaylistId TrackId
-1 3402
-1 3389
-1 3390
-*/
-
-
-CREATE TABLE "Track" (
- "TrackId" INTEGER NOT NULL,
- "Name" NVARCHAR(200) NOT NULL,
- "AlbumId" INTEGER,
- "MediaTypeId" INTEGER NOT NULL,
- "GenreId" INTEGER,
- "Composer" NVARCHAR(220),
- "Milliseconds" INTEGER NOT NULL,
- "Bytes" INTEGER,
- "UnitPrice" NUMERIC(10, 2) NOT NULL,
- PRIMARY KEY ("TrackId"),
- FOREIGN KEY("MediaTypeId") REFERENCES "MediaType" ("MediaTypeId"),
- FOREIGN KEY("GenreId") REFERENCES "Genre" ("GenreId"),
- FOREIGN KEY("AlbumId") REFERENCES "Album" ("AlbumId")
-)
-/*
-3 rows from Track table:
-TrackId Name AlbumId MediaTypeId GenreId Composer Milliseconds Bytes UnitPrice
-1 For Those About To Rock (We Salute You) 1 1 1 Angus Young, Malcolm Young, Brian Johnson 343719 11170334 0.99
-2 Balls to the Wall 2 2 1 U. Dirkschneider, W. Hoffmann, H. Frank, P. Baltes, S. Kaufmann, G. Hoffmann 342562 5510424 0.99
-3 Fast As a Shark 3 2 1 F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman 230619 3990994 0.99
-*/
-```
We can pass this context into the preamble and re-run a query to see how it performs.
-```python PYTHON
+
+```python
preamble="""## Task And Context
You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging.
@@ -624,32 +674,43 @@ Here is information about the database:
""".format(schema_info=context)
```
-```python PYTHON
-output=agent_executor.invoke({
+
+```python
+agent_executor.invoke({
"input": 'provide the name of the best customer? The customer who has spent the most money is the best.',
"preamble": preamble
})
```
-```txt title="Output"
-[1m> Entering new AgentExecutor chain...[0m
-[32;1m[1;3m
-I will write a SQL query to find the customer who has spent the most money.
-{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.CustomerId ORDER BY TotalSpent DESC LIMIT 1;'}}
-[0m[36;1m[1;3m[('Helena', 'Holý', 49.62)][0m[32;1m[1;3mRelevant Documents: 0
-Cited Documents: 0
-Answer: The customer who has spent the most money is Helena Holý.
-Grounded answer: The customer who has spent the most money is Helena Holý.[0m
-
-[1m> Finished chain.[0m
-```
+
+
+ [1m> Entering new AgentExecutor chain...[0m
+ [32;1m[1;3m
+ I will write a SQL query to find the customer who has spent the most money.
+ {'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.CustomerId, c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent\nFROM Customer c\nJOIN Invoice i ON c.CustomerId = i.CustomerId\nGROUP BY c.CustomerId\nORDER BY TotalSpent DESC\nLIMIT 1;'}}
+ [0m[36;1m[1;3m[(6, 'Helena', 'Holý', 49.62)][0m[32;1m[1;3mRelevant Documents: 0
+ Cited Documents: 0
+ Answer: The customer who has spent the most money is Helena Holý.
+ Grounded answer: The customer who has spent the most money is Helena Holý.[0m
+
+ [1m> Finished chain.[0m
-```python PYTHON
-print(output['output'])
-```
-```txt title="Output"
-The customer who has spent the most money is Helena Holý.
-```
-We can see that passing that additional context actually avoids the error seen in the previous section and gets to the answer in one tool call. This works as long as you have a few tables and a few columns per table. We will follow up with more techniques to improve stability and scalability in future work.
+
+
+ {'input': 'provide the name of the best customer? The customer who has spent the most money is the best.',
+ 'preamble': '## Task And Context\nYou use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user\'s needs as best you can, which will be wide-ranging.\n\n## Style Guide\nUnless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling.\n\n## Additional Information\nYou are an expert who answers the user\'s question by creating SQL queries and executing them.\nYou are equipped with a number of relevant SQL tools.\n\nHere is information about the database:\n{\'table_info\': \'\\nCREATE TABLE "Album" (\\n\\t"AlbumId" INTEGER NOT NULL, \\n\\t"Title" NVARCHAR(160) NOT NULL, \\n\\t"ArtistId" INTEGER NOT NULL, \\n\\tPRIMARY KEY ("AlbumId"), \\n\\tFOREIGN KEY("ArtistId") REFERENCES "Artist" ("ArtistId")\\n)\\n\\n/*\\n3 rows from Album table:\\nAlbumId\\tTitle\\tArtistId\\n1\\tFor Those About To Rock We Salute You\\t1\\n2\\tBalls to the Wall\\t2\\n3\\tRestless and Wild\\t2\\n*/\\n\\n\\nCREATE TABLE "Artist" (\\n\\t"ArtistId" INTEGER NOT NULL, \\n\\t"Name" NVARCHAR(120), \\n\\tPRIMARY KEY ("ArtistId")\\n)\\n\\n/*\\n3 rows from Artist table:\\nArtistId\\tName\\n1\\tAC/DC\\n2\\tAccept\\n3\\tAerosmith\\n*/\\n\\n\\nCREATE TABLE "Customer" (\\n\\t"CustomerId" INTEGER NOT NULL, \\n\\t"FirstName" NVARCHAR(40) NOT NULL, \\n\\t"LastName" NVARCHAR(20) NOT NULL, \\n\\t"Company" NVARCHAR(80), \\n\\t"Address" NVARCHAR(70), \\n\\t"City" NVARCHAR(40), \\n\\t"State" NVARCHAR(40), \\n\\t"Country" NVARCHAR(40), \\n\\t"PostalCode" NVARCHAR(10), \\n\\t"Phone" NVARCHAR(24), \\n\\t"Fax" NVARCHAR(24), \\n\\t"Email" NVARCHAR(60) NOT NULL, \\n\\t"SupportRepId" INTEGER, \\n\\tPRIMARY KEY ("CustomerId"), \\n\\tFOREIGN KEY("SupportRepId") REFERENCES "Employee" ("EmployeeId")\\n)\\n\\n/*\\n3 rows from Customer table:\\nCustomerId\\tFirstName\\tLastName\\tCompany\\tAddress\\tCity\\tState\\tCountry\\tPostalCode\\tPhone\\tFax\\tEmail\\tSupportRepId\\n1\\tLuís\\tGonçalves\\tEmbraer - Empresa Brasileira de Aeronáutica S.A.\\tAv. Brigadeiro Faria Lima, 2170\\tSão José dos Campos\\tSP\\tBrazil\\t12227-000\\t+55 (12) 3923-5555\\t+55 (12) 3923-5566\\tluisg@embraer.com.br\\t3\\n2\\tLeonie\\tKöhler\\tNone\\tTheodor-Heuss-Straße 34\\tStuttgart\\tNone\\tGermany\\t70174\\t+49 0711 2842222\\tNone\\tleonekohler@surfeu.de\\t5\\n3\\tFrançois\\tTremblay\\tNone\\t1498 rue Bélanger\\tMontréal\\tQC\\tCanada\\tH2G 1A7\\t+1 (514) 721-4711\\tNone\\tftremblay@gmail.com\\t3\\n*/\\n\\n\\nCREATE TABLE "Employee" (\\n\\t"EmployeeId" INTEGER NOT NULL, \\n\\t"LastName" NVARCHAR(20) NOT NULL, \\n\\t"FirstName" NVARCHAR(20) NOT NULL, \\n\\t"Title" NVARCHAR(30), \\n\\t"ReportsTo" INTEGER, \\n\\t"BirthDate" DATETIME, \\n\\t"HireDate" DATETIME, \\n\\t"Address" NVARCHAR(70), \\n\\t"City" NVARCHAR(40), \\n\\t"State" NVARCHAR(40), \\n\\t"Country" NVARCHAR(40), \\n\\t"PostalCode" NVARCHAR(10), \\n\\t"Phone" NVARCHAR(24), \\n\\t"Fax" NVARCHAR(24), \\n\\t"Email" NVARCHAR(60), \\n\\tPRIMARY KEY ("EmployeeId"), \\n\\tFOREIGN KEY("ReportsTo") REFERENCES "Employee" ("EmployeeId")\\n)\\n\\n/*\\n3 rows from Employee table:\\nEmployeeId\\tLastName\\tFirstName\\tTitle\\tReportsTo\\tBirthDate\\tHireDate\\tAddress\\tCity\\tState\\tCountry\\tPostalCode\\tPhone\\tFax\\tEmail\\n1\\tAdams\\tAndrew\\tGeneral Manager\\tNone\\t1962-02-18 00:00:00\\t2002-08-14 00:00:00\\t11120 Jasper Ave NW\\tEdmonton\\tAB\\tCanada\\tT5K 2N1\\t+1 (780) 428-9482\\t+1 (780) 428-3457\\tandrew@chinookcorp.com\\n2\\tEdwards\\tNancy\\tSales Manager\\t1\\t1958-12-08 00:00:00\\t2002-05-01 00:00:00\\t825 8 Ave SW\\tCalgary\\tAB\\tCanada\\tT2P 2T3\\t+1 (403) 262-3443\\t+1 (403) 262-3322\\tnancy@chinookcorp.com\\n3\\tPeacock\\tJane\\tSales Support Agent\\t2\\t1973-08-29 00:00:00\\t2002-04-01 00:00:00\\t1111 6 Ave SW\\tCalgary\\tAB\\tCanada\\tT2P 5M5\\t+1 (403) 262-3443\\t+1 (403) 262-6712\\tjane@chinookcorp.com\\n*/\\n\\n\\nCREATE TABLE "Genre" (\\n\\t"GenreId" INTEGER NOT NULL, \\n\\t"Name" NVARCHAR(120), \\n\\tPRIMARY KEY ("GenreId")\\n)\\n\\n/*\\n3 rows from Genre table:\\nGenreId\\tName\\n1\\tRock\\n2\\tJazz\\n3\\tMetal\\n*/\\n\\n\\nCREATE TABLE "Invoice" (\\n\\t"InvoiceId" INTEGER NOT NULL, \\n\\t"CustomerId" INTEGER NOT NULL, \\n\\t"InvoiceDate" DATETIME NOT NULL, \\n\\t"BillingAddress" NVARCHAR(70), \\n\\t"BillingCity" NVARCHAR(40), \\n\\t"BillingState" NVARCHAR(40), \\n\\t"BillingCountry" NVARCHAR(40), \\n\\t"BillingPostalCode" NVARCHAR(10), \\n\\t"Total" NUMERIC(10, 2) NOT NULL, \\n\\tPRIMARY KEY ("InvoiceId"), \\n\\tFOREIGN KEY("CustomerId") REFERENCES "Customer" ("CustomerId")\\n)\\n\\n/*\\n3 rows from Invoice table:\\nInvoiceId\\tCustomerId\\tInvoiceDate\\tBillingAddress\\tBillingCity\\tBillingState\\tBillingCountry\\tBillingPostalCode\\tTotal\\n1\\t2\\t2021-01-01 00:00:00\\tTheodor-Heuss-Straße 34\\tStuttgart\\tNone\\tGermany\\t70174\\t1.98\\n2\\t4\\t2021-01-02 00:00:00\\tUllevålsveien 14\\tOslo\\tNone\\tNorway\\t0171\\t3.96\\n3\\t8\\t2021-01-03 00:00:00\\tGrétrystraat 63\\tBrussels\\tNone\\tBelgium\\t1000\\t5.94\\n*/\\n\\n\\nCREATE TABLE "InvoiceLine" (\\n\\t"InvoiceLineId" INTEGER NOT NULL, \\n\\t"InvoiceId" INTEGER NOT NULL, \\n\\t"TrackId" INTEGER NOT NULL, \\n\\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \\n\\t"Quantity" INTEGER NOT NULL, \\n\\tPRIMARY KEY ("InvoiceLineId"), \\n\\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \\n\\tFOREIGN KEY("InvoiceId") REFERENCES "Invoice" ("InvoiceId")\\n)\\n\\n/*\\n3 rows from InvoiceLine table:\\nInvoiceLineId\\tInvoiceId\\tTrackId\\tUnitPrice\\tQuantity\\n1\\t1\\t2\\t0.99\\t1\\n2\\t1\\t4\\t0.99\\t1\\n3\\t2\\t6\\t0.99\\t1\\n*/\\n\\n\\nCREATE TABLE "MediaType" (\\n\\t"MediaTypeId" INTEGER NOT NULL, \\n\\t"Name" NVARCHAR(120), \\n\\tPRIMARY KEY ("MediaTypeId")\\n)\\n\\n/*\\n3 rows from MediaType table:\\nMediaTypeId\\tName\\n1\\tMPEG audio file\\n2\\tProtected AAC audio file\\n3\\tProtected MPEG-4 video file\\n*/\\n\\n\\nCREATE TABLE "Playlist" (\\n\\t"PlaylistId" INTEGER NOT NULL, \\n\\t"Name" NVARCHAR(120), \\n\\tPRIMARY KEY ("PlaylistId")\\n)\\n\\n/*\\n3 rows from Playlist table:\\nPlaylistId\\tName\\n1\\tMusic\\n2\\tMovies\\n3\\tTV Shows\\n*/\\n\\n\\nCREATE TABLE "PlaylistTrack" (\\n\\t"PlaylistId" INTEGER NOT NULL, \\n\\t"TrackId" INTEGER NOT NULL, \\n\\tPRIMARY KEY ("PlaylistId", "TrackId"), \\n\\tFOREIGN KEY("TrackId") REFERENCES "Track" ("TrackId"), \\n\\tFOREIGN KEY("PlaylistId") REFERENCES "Playlist" ("PlaylistId")\\n)\\n\\n/*\\n3 rows from PlaylistTrack table:\\nPlaylistId\\tTrackId\\n1\\t3402\\n1\\t3389\\n1\\t3390\\n*/\\n\\n\\nCREATE TABLE "Track" (\\n\\t"TrackId" INTEGER NOT NULL, \\n\\t"Name" NVARCHAR(200) NOT NULL, \\n\\t"AlbumId" INTEGER, \\n\\t"MediaTypeId" INTEGER NOT NULL, \\n\\t"GenreId" INTEGER, \\n\\t"Composer" NVARCHAR(220), \\n\\t"Milliseconds" INTEGER NOT NULL, \\n\\t"Bytes" INTEGER, \\n\\t"UnitPrice" NUMERIC(10, 2) NOT NULL, \\n\\tPRIMARY KEY ("TrackId"), \\n\\tFOREIGN KEY("MediaTypeId") REFERENCES "MediaType" ("MediaTypeId"), \\n\\tFOREIGN KEY("GenreId") REFERENCES "Genre" ("GenreId"), \\n\\tFOREIGN KEY("AlbumId") REFERENCES "Album" ("AlbumId")\\n)\\n\\n/*\\n3 rows from Track table:\\nTrackId\\tName\\tAlbumId\\tMediaTypeId\\tGenreId\\tComposer\\tMilliseconds\\tBytes\\tUnitPrice\\n1\\tFor Those About To Rock (We Salute You)\\t1\\t1\\t1\\tAngus Young, Malcolm Young, Brian Johnson\\t343719\\t11170334\\t0.99\\n2\\tBalls to the Wall\\t2\\t2\\t1\\tU. Dirkschneider, W. Hoffmann, H. Frank, P. Baltes, S. Kaufmann, G. Hoffmann\\t342562\\t5510424\\t0.99\\n3\\tFast As a Shark\\t3\\t2\\t1\\tF. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman\\t230619\\t3990994\\t0.99\\n*/\', \'table_names\': \'Album, Artist, Customer, Employee, Genre, Invoice, InvoiceLine, MediaType, Playlist, PlaylistTrack, Track\'}\n',
+ 'output': 'The customer who has spent the most money is Helena Holý.',
+ 'citations': [CohereCitation(start=45, end=56, text='Helena Holý', documents=[{'output': "[(6, 'Helena', 'Holý', 49.62)]"}])],
+ 'intermediate_steps': [(AgentActionMessageLog(tool='sql_db_query', tool_input={'query': 'SELECT c.CustomerId, c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent\nFROM Customer c\nJOIN Invoice i ON c.CustomerId = i.CustomerId\nGROUP BY c.CustomerId\nORDER BY TotalSpent DESC\nLIMIT 1;'}, log="\nI will write a SQL query to find the customer who has spent the most money.\n{'tool_name': 'sql_db_query', 'parameters': {'query': 'SELECT c.CustomerId, c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent\\nFROM Customer c\\nJOIN Invoice i ON c.CustomerId = i.CustomerId\\nGROUP BY c.CustomerId\\nORDER BY TotalSpent DESC\\nLIMIT 1;'}}\n", message_log=[AIMessage(content='\nPlan: I will write a SQL query to find the customer who has spent the most money.\nAction: ```json\n[\n {\n "tool_name": "sql_db_query",\n "parameters": {\n "query": "SELECT c.CustomerId, c.FirstName, c.LastName, SUM(i.Total) AS TotalSpent\\nFROM Customer c\\nJOIN Invoice i ON c.CustomerId = i.CustomerId\\nGROUP BY c.CustomerId\\nORDER BY TotalSpent DESC\\nLIMIT 1;"\n }\n }\n]\n```')]),
+ "[(6, 'Helena', 'Holý', 49.62)]")]}
+
+
+
+Great, we can see that passing that additional context actually avoids the error seen in the previous section and gets to the answer in one tool call. Of course this works as long as you have a few tables and a few columns per table. We will follow up with more techniques to improve stability and scalability in another notebook.
+
+
+```python
+
+```
diff --git a/fern/pages/cookbooks/summarization-evals.mdx b/fern/pages/cookbooks/summarization-evals.mdx
index 908901068..3cae6e675 100644
--- a/fern/pages/cookbooks/summarization-evals.mdx
+++ b/fern/pages/cookbooks/summarization-evals.mdx
@@ -1,28 +1,44 @@
---
-title: Evaluating Text Summarization Models
+title: Summarization Evals
slug: /page/summarization-evals
description: "This page discusses how to evaluate a model's text summarization."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, text summarization"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
+
+
+
In this cookbook, we will be demonstrating an approach we use for evaluating summarization tasks using LLM evaluation.
-# Get Started [#start]
+### Table of contents:
+1. [Get started](#start)
+2. [Construct the evaluation dataset](#dataset)
+3. [Build the evaluation framework](#eval-framework)
+5. [Run evaluations](#run-evals)
+
+
+
+# Get Started
You'll need a Cohere API key to run this notebook. If you don't have a key, head to https://cohere.com/ to generate your key.
-```python PYTHON
-!pip install cohere datasets --quiet
+
+```python
+# %%capture
+!pip install "cohere<5" datasets --quiet
```
-```python PYTHON
+
+```python
import json
import random
import re
@@ -33,6 +49,7 @@ from getpass import getpass
from datasets import load_dataset
import pandas as pd
+# Set up Cohere client
co_api_key = getpass("Enter your Cohere API key: ")
co_model = "command-r"
co = cohere.Client(api_key=co_api_key)
@@ -40,39 +57,29 @@ co = cohere.Client(api_key=co_api_key)
As test data, we'll use transcripts from the [QMSum dataset](https://github.com/Yale-LILY/QMSum). Note that in addition to the transcripts, this dataset also contains reference summaries -- we will use only the transcripts as our approach is reference-free.
-```python PYTHON
+
+```python
qmsum = load_dataset("MocktaiLEngineer/qmsum-processed", split="validation")
transcripts = [x for x in qmsum["meeting_transcript"] if x is not None]
```
-```txt title="Output"
-Generating train split: 0%| | 0/1095 [00:00, ? examples/s]
-
-
-
-Generating validation split: 0%| | 0/237 [00:00, ? examples/s]
-
-
-
-Generating test split: 0%| | 0/244 [00:00, ? examples/s]
-```
-
-# Construct the evaluation dataset [#dataset]
+
+
+# Construct the evaluation dataset
We are interested in evaluating summarization in real-world, enterprise use cases, which typically have two distinguishing features as compared to academic summarization benchmarks:
-
- Enterprise use cases often focus on specific summarization objectives, e.g. "summarize action items".
- Enterprise use cases often feature specific instruction constraints, e.g. "summarize in bullets with each bullet under 20 words".
Therefore, we must first create a dataset that contains diverse summarization prompts. We will do this programmatically by building prompts from their components, as defined below:
-
- Prompt = text (e.g. transcript to be summarized) + instruction
- Instruction = instruction objective (e.g. "summarize action items") + modifiers
- Modifiers = format/length modifiers (e.g. "use bullets") + style/tone modifiers (e.g. "do not mention names") + ...
First, we define the prompt that combines the text and instructions. Here, we use a very basic prompt:
-```python PYTHON
+
+```python
prompt_template = """## meeting transcript
{transcript}
@@ -82,13 +89,17 @@ prompt_template = """## meeting transcript
Next, we build the instructions. Because each instruction may have a different objective and modifiers, we track them using metadata. This will later be required for evaluation (i.e. to know what the prompt is asking).
-```python PYTHON
+
+```python
+# In this cookbook, we will only consider the following 2 objectives and 4 format/length modifiers
instruction_objectives = {
"general_summarization": "Summarize the meeting based on the transcript.",
"action_items": "What are the follow-up items based on the meeting transcript?",
}
+# Note that not all format/length modifiers are compatible with all objectives. For example, action
+# items are best suited for bullet format.
format_length_modifiers = {
"paragraphs_short": {
"text": "In paragraph form, output your response. Use at least 10 words and at most 50 words in total.",
@@ -133,7 +144,8 @@ format_length_modifiers = {
Let's combine the objectives and format/length modifiers to finish building the instructions.
-```python PYTHON
+
+```python
instructions = []
for obj_name, obj_text in instruction_objectives.items():
for mod_data in format_length_modifiers.values():
@@ -146,114 +158,125 @@ for obj_name, obj_text in instruction_objectives.items():
}
instructions.append(instruction)
+# View the first two instructions
print(json.dumps(instructions[:2], indent=4))
```
-```python title="Output"
-[
- {
- "instruction": "Summarize the meeting based on the transcript. In paragraph form, output your response. Use at least 10 words and at most 50 words in total.",
- "eval_metadata": {
- "format": "paragraphs",
- "min_length": 10,
- "max_length": 50
+ [
+ {
+ "instruction": "Summarize the meeting based on the transcript. In paragraph form, output your response. Use at least 10 words and at most 50 words in total.",
+ "eval_metadata": {
+ "format": "paragraphs",
+ "min_length": 10,
+ "max_length": 50
+ },
+ "objective": "general_summarization"
},
- "objective": "general_summarization"
- },
- {
- "instruction": "Summarize the meeting based on the transcript. Return the answer in the form of paragraphs. Make sure your answer is between 50 and 200 words long.",
- "eval_metadata": {
- "format": "paragraphs",
- "min_length": 50,
- "max_length": 200
- },
- "objective": "general_summarization"
- }
-]
-```
+ {
+ "instruction": "Summarize the meeting based on the transcript. Return the answer in the form of paragraphs. Make sure your answer is between 50 and 200 words long.",
+ "eval_metadata": {
+ "format": "paragraphs",
+ "min_length": 50,
+ "max_length": 200
+ },
+ "objective": "general_summarization"
+ }
+ ]
+
Finally, let's build the final prompts by semi-randomly pairing the instructions with transcripts from the QMSum dataset.
-```python PYTHON
+
+```python
data = pd.DataFrame(instructions)
+# Randomly shuffle the top 25% of transcripts by length, then assign them to the data
transcripts = sorted(transcripts, key=lambda x: len(x), reverse=True)[:int(len(transcripts) * 0.25)]
random.seed(42)
random.shuffle(transcripts)
data["transcript"] = transcripts[:len(data)]
+# Build the prompt
data["prompt"] = data.apply(lambda x: prompt_template.format(transcript=x["transcript"], instructions=x["instruction"]), axis=1)
```
-```python PYTHON
-data["transcript_token_len"] = [len(x) for x in co.batch_tokenize(data["transcript"].tolist(), model=co_model)]
-```
-```python PYTHON
-print(data["prompt"][0])
+```python
+# (Optional) Let's also check the token lengths of our prompts.
+data["transcript_token_len"] = [len(x) for x in co.batch_tokenize(data["transcript"].tolist(), model=co_model)]
```
-```txt title="Output"
-## meeting transcript
-PhD F: As opposed to the rest of us
-PhD D: Well comment OK I I remind that me my first objective eh in the project is to to study difference parameters to to find a a good solution to detect eh the overlapping zone in eh speech recorded But eh tsk comment ehhh comment In that way comment I I I begin to to study and to analyze the ehn the recorded speech eh the different session to to find and to locate and to mark eh the the different overlapping zone And eh so eh I was eh I am transcribing the the first session and I I have found eh eh one thousand acoustic events eh besides the overlapping zones eh I I I mean the eh breaths eh aspiration eh eh talk eh eh clap eh comment I do not know what is the different names eh you use to to name the the pause n speech
-Grad G: Oh I do not think we ve been doing it at that level of detail So
-PhD D: Eh I I I do I do not need to to to mmm to m to label the the different acoustic but I prefer because eh I would like to to study if eh I I will find eh eh a good eh parameters eh to detect overlapping I would like to to to test these parameters eh with the another eh eh acoustic events to nnn to eh to find what is the ehm the false eh the false eh hypothesis eh nnn which eh are produced when we use the the ehm this eh parameter eh I mean pitch eh eh difference eh feature
-PhD A: You know I think some of these that are the nonspeech overlapping events may be difficult even for humans to tell that there s two there I mean if it s a tapping sound you would not necessarily or you know something like that it would be it might be hard to know that it was two separate events
-Grad G: Well You were not talking about just overlaps were you ? You were just talking about acoustic events
-PhD D: I I I I t I t I talk eh about eh acoustic events in general but eh my my objective eh will be eh to study eh overlapping zone Eh ? comment n Eh in twelve minutes I found eh eh one thousand acoustic events
-Professor E: How many overlaps were there in it ? No no how many of them were the overlaps of speech though ?
-PhD D: How many ? Eh almost eh three hundred eh in one session in five eh in forty five minutes Alm Three hundred overlapping zone With the overlapping zone overlapping speech speech what eh different duration
-Postdoc B: Does this ? So if you had an overlap involving three people how many times was that counted ?
-PhD D: three people two people Eh I would like to consider eh one people with difference noise eh in the background be
-Professor E: No no but I think what she s asking is pause if at some particular for some particular stretch you had three people talking instead of two did you call that one event ?
-PhD D: Oh Oh I consider one event eh for th for that eh for all the zone This th I I I con I consider I consider eh an acoustic event the overlapping zone the period where three speaker or eh are talking together
-Grad G: So let s say me and Jane are talking at the same time and then Liz starts talking also over all of us How many events would that be ?
-PhD D: So I do not understand
-Grad G: So two people are talking comment and then a third person starts talking Is there an event right here ?
-PhD D: Eh no No no For me is the overlapping zone because because you you have s you have more one eh more one voice eh eh produced in a in in a moment
-Grad G: So i if two or more people are talking
-Professor E: OK So I think We just wanted to understand how you are defining it So then in the region between since there there is some continuous region in between regions where there is only one person speaking And one contiguous region like that you are calling an event Is it Are you calling the beginning or the end of it the event or are you calling the entire length of it the event ?
-PhD D: I consider the the nnn the nnn nnn eh the entirety eh eh all all the time there were the voice has overlapped This is the idea But eh I I do not distinguish between the the numbers of eh speaker I m not considering eh the the ehm eh the fact of eh eh for example what did you say ? Eh at first eh eh two talkers are eh speaking and eh eh a third person eh join to to that For me it s eh it s eh all overlap zone with eh several numbers of speakers is eh eh the same acoustic event Wi but without any mark between the zone of the overlapping zone with two speakers eh speaking together and the zone with the three speakers
-Postdoc B: That would j just be one
-PhD D: Eh with eh a beginning mark and the ending mark Because eh for me is the is the zone with eh some kind of eh distortion the spectral I do not mind By the moment by the moment
-Grad G: Well but But you could imagine that three people talking has a different spectral characteristic than two
-PhD D: I I do not but eh but eh I have to study comment What will happen in a general way
-Grad G: So You had to start somewhere
-PhD C: So there s a lot of overlap
-PhD D: I I do not know what eh will will happen with the
-Grad G: That s a lot of overlap
-Professor E: So again that s that s three three hundred in forty five minutes that are that are speakers just speakers
-Postdoc B: But a a a th
-Professor E: So that s about eight per minute
-Postdoc B: But a thousand events in twelve minutes that s
-PhD C: But that can include taps
-Postdoc B: Well but a thousand taps in eight minutes is a l in twelve minutes is a lot
-PhD D: I I con I consider I consider acoustic events eh the silent too
-Grad G: Silence starting or silence ending
-PhD D: silent ground to bec to detect eh because I consider acoustic event all the things are not eh speech In ge in in in a general point of view
-Professor E: OK so how many of those thousand were silence ?
-PhD F: Not speech not speech or too much speech
-Professor E: Right So how many of those thousand were silence silent sections ?
-PhD D: silent I I I I do not I I have not the eh I I would like to to do a stylistic study
-## instructions
-Summarize the meeting based on the transcript. In paragraph form, output your response. Use at least 10 words and at most 50 words in total.
+```python
+# Let's examine one of the prompts
+print(data["prompt"][0])
```
-# Build the evaluation framework [#eval-framework]
+ ## meeting transcript
+ PhD F: As opposed to the rest of us
+ PhD D: Well comment OK I I remind that me my first objective eh in the project is to to study difference parameters to to find a a good solution to detect eh the overlapping zone in eh speech recorded But eh tsk comment ehhh comment In that way comment I I I begin to to study and to analyze the ehn the recorded speech eh the different session to to find and to locate and to mark eh the the different overlapping zone And eh so eh I was eh I am transcribing the the first session and I I have found eh eh one thousand acoustic events eh besides the overlapping zones eh I I I mean the eh breaths eh aspiration eh eh talk eh eh clap eh comment I do not know what is the different names eh you use to to name the the pause n speech
+ Grad G: Oh I do not think we ve been doing it at that level of detail So
+ PhD D: Eh I I I do I do not need to to to mmm to m to label the the different acoustic but I prefer because eh I would like to to study if eh I I will find eh eh a good eh parameters eh to detect overlapping I would like to to to test these parameters eh with the another eh eh acoustic events to nnn to eh to find what is the ehm the false eh the false eh hypothesis eh nnn which eh are produced when we use the the ehm this eh parameter eh I mean pitch eh eh difference eh feature
+ PhD A: You know I think some of these that are the nonspeech overlapping events may be difficult even for humans to tell that there s two there I mean if it s a tapping sound you would not necessarily or you know something like that it would be it might be hard to know that it was two separate events
+ Grad G: Well You were not talking about just overlaps were you ? You were just talking about acoustic events
+ PhD D: I I I I t I t I talk eh about eh acoustic events in general but eh my my objective eh will be eh to study eh overlapping zone Eh ? comment n Eh in twelve minutes I found eh eh one thousand acoustic events
+ Professor E: How many overlaps were there in it ? No no how many of them were the overlaps of speech though ?
+ PhD D: How many ? Eh almost eh three hundred eh in one session in five eh in forty five minutes Alm Three hundred overlapping zone With the overlapping zone overlapping speech speech what eh different duration
+ Postdoc B: Does this ? So if you had an overlap involving three people how many times was that counted ?
+ PhD D: three people two people Eh I would like to consider eh one people with difference noise eh in the background be
+ Professor E: No no but I think what she s asking is pause if at some particular for some particular stretch you had three people talking instead of two did you call that one event ?
+ PhD D: Oh Oh I consider one event eh for th for that eh for all the zone This th I I I con I consider I consider eh an acoustic event the overlapping zone the period where three speaker or eh are talking together
+ Grad G: So let s say me and Jane are talking at the same time and then Liz starts talking also over all of us How many events would that be ?
+ PhD D: So I do not understand
+ Grad G: So two people are talking comment and then a third person starts talking Is there an event right here ?
+ PhD D: Eh no No no For me is the overlapping zone because because you you have s you have more one eh more one voice eh eh produced in a in in a moment
+ Grad G: So i if two or more people are talking
+ Professor E: OK So I think We just wanted to understand how you are defining it So then in the region between since there there is some continuous region in between regions where there is only one person speaking And one contiguous region like that you are calling an event Is it Are you calling the beginning or the end of it the event or are you calling the entire length of it the event ?
+ PhD D: I consider the the nnn the nnn nnn eh the entirety eh eh all all the time there were the voice has overlapped This is the idea But eh I I do not distinguish between the the numbers of eh speaker I m not considering eh the the ehm eh the fact of eh eh for example what did you say ? Eh at first eh eh two talkers are eh speaking and eh eh a third person eh join to to that For me it s eh it s eh all overlap zone with eh several numbers of speakers is eh eh the same acoustic event Wi but without any mark between the zone of the overlapping zone with two speakers eh speaking together and the zone with the three speakers
+ Postdoc B: That would j just be one
+ PhD D: Eh with eh a beginning mark and the ending mark Because eh for me is the is the zone with eh some kind of eh distortion the spectral I do not mind By the moment by the moment
+ Grad G: Well but But you could imagine that three people talking has a different spectral characteristic than two
+ PhD D: I I do not but eh but eh I have to study comment What will happen in a general way
+ Grad G: So You had to start somewhere
+ PhD C: So there s a lot of overlap
+ PhD D: I I do not know what eh will will happen with the
+ Grad G: That s a lot of overlap
+ Professor E: So again that s that s three three hundred in forty five minutes that are that are speakers just speakers
+ Postdoc B: But a a a th
+ Professor E: So that s about eight per minute
+ Postdoc B: But a thousand events in twelve minutes that s
+ PhD C: But that can include taps
+ Postdoc B: Well but a thousand taps in eight minutes is a l in twelve minutes is a lot
+ PhD D: I I con I consider I consider acoustic events eh the silent too
+ Grad G: Silence starting or silence ending
+ PhD D: silent ground to bec to detect eh because I consider acoustic event all the things are not eh speech In ge in in in a general point of view
+ Professor E: OK so how many of those thousand were silence ?
+ PhD F: Not speech not speech or too much speech
+ Professor E: Right So how many of those thousand were silence silent sections ?
+ PhD D: silent I I I I do not I I have not the eh I I would like to to do a stylistic study
+
+ ## instructions
+ Summarize the meeting based on the transcript. In paragraph form, output your response. Use at least 10 words and at most 50 words in total.
+
+
+
+
+# Build the evaluation framework
We now setup the tools we will use for evaluation.
We use three criteria that are graded using LLMs:
-
- Completeness: checks if the summary includes all the important information from the original text that it should include
- Correctness: checks if there are any hallucinations or factual inaccuracies in the summary
- Conciseness: checks if the summary includes any unnecessary information or wordiness
In this cookbook, we will use Command-R to grade the completions. However, note that in practice, we typically use an ensemble of multiple LLM evaluators to reduce any bias.
-```python PYTHON
+
+```python
+# LLM evaluation uses an LLM to grade the completion. We pass the original prompt, completion, and a
+# criteria to the LLM, and it returns a score between 1 and 5. We will use the following template as
+# the grading prompt.
grading_prompt_template = """You are an AI grader that given a prompt, a completion, and a criterion, grades the completion based on the prompt and criterion. Below is a prompt, a completion, and a criterion with which to grade the completion. You need to respond according to the criterion instructions.
@@ -304,11 +327,12 @@ def score_llm(prompt: str, completion: str, criteria: str) -> int:
```
In addition, we have two criteria that are graded programmatically:
-
- Format: checks if the summary follows the format (e.g. bullets) that was requested in the prompt
- Length: checks if the summary follows the length that was requested in the prompt.
-```python PYTHON
+
+```python
+# Non-LLM checks
def score_format(completion: str, format_type: str) -> int:
"""
@@ -389,13 +413,16 @@ def _extract_markdown_bullets(text: str, include_bullet: bool = False) -> List[s
```
-# Run evaluations [#run-evals]
+
+
+# Run evaluations
Now that we have our evaluation dataset and defined our evaluation functions, let's run evaluations!
First, we generate completions to be graded. We will use Cohere's [Command-R](https://huggingface.co/CohereForAI/c4ai-command-r-v01) model, boasting a context length of 128K.
-```python PYTHON
+
+```python
completions = []
for prompt in data["prompt"]:
completion = co.chat(message=prompt, model="command-r", temperature=0.2).text
@@ -404,19 +431,25 @@ for prompt in data["prompt"]:
data["completion"] = completions
```
-```python PYTHON
+
+```python
+# Let's look at the completion for the example prompt we showed earlier
print(data["completion"][0])
```
- PhD D is transcribing recorded sessions to locate overlapping speech zones and categorizing them as acoustic events. The team discusses the parameters PhD D should use and how to define these events, considering the number of speakers and silence.
+ PhD student D presented their method for detecting and counting acoustic events in recorded speech sessions, including speech overlaps and silence. The team sought clarification on D's definitions and counted events, discussing the challenges of distinguishing between different types of events.
+
Let's grade the completions using our LLM and non-LLM checks.
-```python PYTHON
+
+```python
+# Score format
data["format_score"] = data.apply(
lambda x: score_format(x["completion"], x["eval_metadata"]["format"]), axis=1
)
+# Score length
data["length_score"] = data.apply(
lambda x: score_length(
x["completion"],
@@ -427,149 +460,337 @@ data["length_score"] = data.apply(
axis=1,
)
+# Score completeness
data["completeness_score"] = data.apply(
lambda x: score_llm(x["prompt"], x["completion"], criteria_completeness), axis=1
)
+# Score correctness
data["correctness_score"] = data.apply(
lambda x: score_llm(x["prompt"], x["completion"], criteria_correctness), axis=1
)
+# Score conciseness
data["conciseness_score"] = data.apply(
lambda x: score_llm(x["prompt"], x["completion"], criteria_conciseness), axis=1
)
```
-```python PYTHON
+
+```python
+# Let's examine the final evaluation results
data
```
-
-
-
-
- |
-instruction |
-eval_metadata |
-objective |
-transcript |
-prompt |
-transcript_token_len |
-completion |
-format_score |
-length_score |
-completeness_score |
-correctness_score |
-conciseness_score |
-
-
-
-
-0 |
-Summarize the meeting based on the transcript.... |
-\{'format': 'paragraphs', 'min_length': 10, 'ma... |
-general_summarization |
-PhD F: As opposed to the rest of us \nPhD D: W... |
-## meeting transcript\nPhD F: As opposed to th... |
-1378 |
-PhD D is transcribing recorded sessions to loc... |
-1 |
-1 |
-0.8 |
-1.0 |
-0.8 |
-
-
-1 |
-Summarize the meeting based on the transcript.... |
-\{'format': 'paragraphs', 'min_length': 50, 'ma... |
-general_summarization |
-Lynne Neagle AM: Thank you very much And the n... |
-## meeting transcript\nLynne Neagle AM: Thank ... |
-1649 |
-The discussion focused on the impact of COVID1... |
-1 |
-1 |
-0.8 |
-1.0 |
-0.8 |
-
-
-2 |
-Summarize the meeting based on the transcript.... |
-\{'format': 'bullets', 'number': 3, 'min_length... |
-general_summarization |
-Industrial Designer: Yep So we are to mainly d... |
-## meeting transcript\nIndustrial Designer: Ye... |
-1100 |
-- The team is designing a remote control with ... |
-1 |
-0 |
-0.8 |
-1.0 |
-0.8 |
-
-
-3 |
-Summarize the meeting based on the transcript.... |
-\{'format': 'bullets', 'number': 2, 'min_length... |
-general_summarization |
-Industrial Designer: Mm I think one of the ver... |
-## meeting transcript\nIndustrial Designer: Mm... |
-2618 |
-- The team discusses the target demographic fo... |
-1 |
-1 |
-0.8 |
-1.0 |
-0.8 |
-
-
-4 |
-What are the follow-up items based on the meet... |
-\{'format': 'bullets', 'number': 3, 'min_length... |
-action_items |
-Marketing: so a lot of people have to be able ... |
-## meeting transcript\nMarketing: so a lot of ... |
-2286 |
-- Investigate how the remote will interact wit... |
-1 |
-1 |
-0.8 |
-1.0 |
-0.8 |
-
-
-5 |
-What are the follow-up items based on the meet... |
-\{'format': 'bullets', 'number': 2, 'min_length... |
-action_items |
-Project Manager: Alright So finance And we wil... |
-## meeting transcript\nProject Manager: Alrigh... |
-1965 |
-- The project manager will send the updated de... |
-1 |
-1 |
-0.8 |
-1.0 |
-0.8 |
-
-
+
+
+
+
+
+
+
+
+
+
+ |
+ instruction |
+ eval_metadata |
+ objective |
+ transcript |
+ prompt |
+ transcript_token_len |
+ completion |
+ format_score |
+ length_score |
+ completeness_score |
+ correctness_score |
+ conciseness_score |
+
+
+
+
+ 0 |
+ Summarize the meeting based on the transcript.... |
+ {'format': 'paragraphs', 'min_length': 10, 'ma... |
+ general_summarization |
+ PhD F: As opposed to the rest of us \nPhD D: W... |
+ ## meeting transcript\nPhD F: As opposed to th... |
+ 1378 |
+ PhD student D presented their method for detec... |
+ 1 |
+ 1 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+ 1 |
+ Summarize the meeting based on the transcript.... |
+ {'format': 'paragraphs', 'min_length': 50, 'ma... |
+ general_summarization |
+ Lynne Neagle AM: Thank you very much And the n... |
+ ## meeting transcript\nLynne Neagle AM: Thank ... |
+ 1649 |
+ The meeting between Welsh politicians and offi... |
+ 1 |
+ 1 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+ 2 |
+ Summarize the meeting based on the transcript.... |
+ {'format': 'bullets', 'number': 3, 'min_length... |
+ general_summarization |
+ Industrial Designer: Yep So we are to mainly d... |
+ ## meeting transcript\nIndustrial Designer: Ye... |
+ 1100 |
+ - The team discusses the design of a remote co... |
+ 1 |
+ 0 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+ 3 |
+ Summarize the meeting based on the transcript.... |
+ {'format': 'bullets', 'number': 2, 'min_length... |
+ general_summarization |
+ Industrial Designer: Mm I think one of the ver... |
+ ## meeting transcript\nIndustrial Designer: Mm... |
+ 2618 |
+ - The team discusses the target demographic fo... |
+ 1 |
+ 1 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+ 4 |
+ What are the follow-up items based on the meet... |
+ {'format': 'bullets', 'number': 3, 'min_length... |
+ action_items |
+ Marketing: so a lot of people have to be able ... |
+ ## meeting transcript\nMarketing: so a lot of ... |
+ 2286 |
+ - Investigate remote's compatibility with vari... |
+ 1 |
+ 1 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+ 5 |
+ What are the follow-up items based on the meet... |
+ {'format': 'bullets', 'number': 2, 'min_length... |
+ action_items |
+ Project Manager: Alright So finance And we wil... |
+ ## meeting transcript\nProject Manager: Alrigh... |
+ 1965 |
+ - The project manager will send the updated de... |
+ 1 |
+ 1 |
+ 0.8 |
+ 1.0 |
+ 0.8 |
+
+
+
+
+
+
-Finally, let's print the average scores per critiera.
-```python PYTHON
+Finally, let's plot the average scores per critiera.
+
+
+```python
avg_scores = data[["format_score", "length_score", "completeness_score", "correctness_score", "conciseness_score"]].mean()
-print(avg_scores)
+ax = avg_scores.plot.bar(title="Average Scores", xlabel="Criteria", ylabel="Score")
```
-```txt title="Output"
-format_score 1.000000
-length_score 0.833333
-completeness_score 0.800000
-correctness_score 1.000000
-conciseness_score 0.800000
-dtype: float64
-```
+
+
+
+
+
diff --git a/fern/pages/cookbooks/text-classification-using-embeddings.mdx b/fern/pages/cookbooks/text-classification-using-embeddings.mdx
index 351b4f139..ae9f88ee8 100644
--- a/fern/pages/cookbooks/text-classification-using-embeddings.mdx
+++ b/fern/pages/cookbooks/text-classification-using-embeddings.mdx
@@ -3,22 +3,21 @@ title: Text Classification Using Embeddings
slug: /page/text-classification-using-embeddings
description: "This page discusses the creation of a text classification model using word vector embeddings."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, text classification, classification models, word vector embeddings"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-This notebook shows how to build a classifier using Cohere's embeddings.
-
+
+
+This notebook shows how to build a classifiers using Cohere's embeddings.
+
The example classification task here will be sentiment analysis of film reviews. We'll train a simple classifier to detect whether a film review is negative (class 0) or positive (class 1).
@@ -29,95 +28,113 @@ We'll go through the following steps:
3. Train a classifier using the training set
4. Evaluate the performance of the classifier on the testing set
+
+```python
+# Let's first install Cohere's python SDK
+# TODO: upgrade to "cohere>5"!pip install "cohere<5" scikit-learn
+```
+
If you're running an older version of the SDK you'll want to upgrade it, like this:
-```python PYTHON
+
+```python
#!pip install --upgrade cohere
```
## 1. Get the dataset
-```python PYTHON
+
+```python
import cohere
from sklearn.model_selection import train_test_split
import pandas as pd
pd.set_option('display.max_colwidth', None)
+# Get the SST2 training and test sets
df = pd.read_csv('https://github.com/clairett/pytorch-sentiment-classification/raw/master/data/SST2/train.tsv', delimiter='\t', header=None)
```
-```python PYTHON
+
+```python
+# Let's glance at the dataset
df.head()
```
+
+
+
-
-
-
- |
- 0 |
- 1 |
-
-
-
-
- 0 |
-
- a stirring , funny and finally transporting re imagining of beauty and
- the beast and 1930s horror films
- |
- 1 |
-
-
- 1 |
-
- apparently reassembled from the cutting room floor of any given
- daytime soap
- |
- 0 |
-
-
- 2 |
-
- they presume their audience wo n't sit still for a sociology lesson ,
- however entertainingly presented , so they trot out the conventional
- science fiction elements of bug eyed monsters and futuristic women in
- skimpy clothes
- |
- 0 |
-
-
- 3 |
-
- this is a visually stunning rumination on love , memory , history and
- the war between art and commerce
- |
- 1 |
-
-
- 4 |
-
- jonathan parker 's bartleby should have been the be all end all of the
- modern office anomie films
- |
- 1 |
-
-
-
+
+
+
+
+ |
+ 0 |
+ 1 |
+
+
+
+
+ 0 |
+ a stirring , funny and finally transporting re imagining of beauty and the beast and 1930s horror films |
+ 1 |
+
+
+ 1 |
+ apparently reassembled from the cutting room floor of any given daytime soap |
+ 0 |
+
+
+ 2 |
+ they presume their audience wo n't sit still for a sociology lesson , however entertainingly presented , so they trot out the conventional science fiction elements of bug eyed monsters and futuristic women in skimpy clothes |
+ 0 |
+
+
+ 3 |
+ this is a visually stunning rumination on love , memory , history and the war between art and commerce |
+ 1 |
+
+
+ 4 |
+ jonathan parker 's bartleby should have been the be all end all of the modern office anomie films |
+ 1 |
+
+
+
+
+
We'll only use a subset of the training and testing datasets in this example. We'll only use 500 examples since this is a toy example. You'll want to increase the number to get better performance and evaluation.
The `train_test_split` method splits arrays or matrices into random train and test subsets.
-```python PYTHON
+
+```python
+# Set the number of examples from the dataset
num_examples = 500
+# Create a dataframe that
df_sample = df.sample(num_examples)
+# Split into training and testing sets
sentences_train, sentences_test, labels_train, labels_test = train_test_split(
list(df_sample[0]), list(df_sample[1]), test_size=0.25, random_state=0)
+# The embeddings endpoint can take up to 96 texts, so we'll have to truncate
+# sentences_train, sentences_test, labels_train, and labels_test.
sentences_train = sentences_train[:95]
sentences_test = sentences_test[:95]
@@ -127,78 +144,94 @@ labels_test = labels_test[:95]
```
## 2. Set up the Cohere client and get the embeddings of the reviews
+We're now ready to retrieve the embeddings from the API. You'll need your API key for this next cell. [Sign up to Cohere](https://os.cohere.ai/) and get one if you haven't yet.
-We're now ready to retrieve the embeddings from the API. You'll need your API key for this next cell. [Sign up to Cohere](https://dashboard.cohere.com/) and get one if you haven't yet.
-```python PYTHON
+```python
+# Add the model name, API key, URL, etc.
model_name = "embed-english-v3.0"
api_key = ""
+# Here, we're setting up the data objects we'll pass to the embeds endpoint.
input_type = "classification"
+# Create and retrieve a Cohere API key from dashboard.cohere.ai
co = cohere.Client(api_key)
```
-```python PYTHON
+
+```python
+# Embed the training set
embeddings_train = co.embed(texts=sentences_train,
model=model_name,
input_type=input_type
).embeddings
+# Embed the testing set
embeddings_test = co.embed(texts=sentences_test,
model=model_name,
input_type=input_type
).embeddings
+# Here we are using the endpoint co.embed()
```
Note that the ordering of the arguments is important. If you put `input_type` in before `model_name`, you'll get an error.
-We now have two sets of embeddings, `embeddings_train` contains the embeddings of the training sentences while `embeddings_test` contains the embeddings of the testing sentences.
+We now have two sets of embeddings, `embeddings_train` contains the embeddings of the training sentences while `embeddings_test` contains the embeddings of the testing sentences.
+
+Curious what an embedding looks like? we can print it:
-Curious what an embedding looks like? We can print it:
-```python PYTHON
+```python
print(f"Review text: {sentences_train[0]}")
print(f"Embedding vector: {embeddings_train[0][:10]}")
```
-```
-Review text: the script was reportedly rewritten a dozen times either 11 times too many or else too few
-Embedding vector: [1.1531117, -0.8543223, -1.2496399, -0.28317127, -0.75870246, 0.5373464, 0.63233083, 0.5766576, 1.8336298, 0.44203663]
-```
+ Review text: the script was reportedly rewritten a dozen times either 11 times too many or else too few
+ Embedding vector: [1.1531117, -0.8543223, -1.2496399, -0.28317127, -0.75870246, 0.5373464, 0.63233083, 0.5766576, 1.8336298, 0.44203663]
+
## 3. Train a classifier using the training set
+Now that we have the embedding we can train our classifier. We'll use an SVM from sklearn.
-Now that we have the embedding, we can train our classifier. We'll use an SVM from sklearn.
-```python PYTHON
+```python
+# import SVM classifier code
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
-svm_classifier = make_pipeline(StandardScaler(), SVC(class_weight='balanced'))
+# Initialize a support vector machine, with class_weight='balanced' because
+# our training set has roughly an equal amount of positive and negative
+# sentiment sentences
+svm_classifier = make_pipeline(StandardScaler(), SVC(class_weight='balanced'))
+# fit the support vector machine
svm_classifier.fit(embeddings_train, labels_train)
```
-```
-Pipeline(steps=[('standardscaler', StandardScaler()),
- ('svc', SVC(class_weight='balanced'))])
-```
+
+
+
+ Pipeline(steps=[('standardscaler', StandardScaler()),
+ ('svc', SVC(class_weight='balanced'))])
+
+
## 4. Evaluate the performance of the classifier on the testing set
-```python PYTHON
+
+```python
+# get the score from the test set, and print it out to screen!
score = svm_classifier.score(embeddings_test, labels_test)
print(f"Validation accuracy on is {100*score}%!")
```
-```
-Validation accuracy on Large is 91.2%!
-```
+ Validation accuracy on Large is 91.2%!
+
You may get a slightly different number when you run this code.
diff --git a/fern/pages/cookbooks/topic-modeling-ai-papers.mdx b/fern/pages/cookbooks/topic-modeling-ai-papers.mdx
index d661132d2..b3fb83e46 100644
--- a/fern/pages/cookbooks/topic-modeling-ai-papers.mdx
+++ b/fern/pages/cookbooks/topic-modeling-ai-papers.mdx
@@ -1,43 +1,55 @@
---
-title: Topic Modeling System for AI Papers
+title: Topic Modeling AI Papers
slug: /page/topic-modeling-ai-papers
description: "This page discusses how to create a topic-modeling system for papers focused on AI papers."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, topic modeling, automated science"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
+
+
+
Natural Language Processing (NLP) is a hot topic in machine learning. It involves analyzing and understanding text-based data. Clustering algorithms are quite popular in NLP. They group a set of unlabeled texts in such a way that texts in the same cluster are more like one another. Topic modeling is one application of clustering in NLP. It uses unsupervised learning to extract topics from a collection of documents. Other applications include automatic document organization and fast information retrieval or filtering.
You'll learn how to use Cohere’s NLP tools to perform semantic search and clustering of AI Papers. This will help you discover trends in AI. You'll scrape the Journal of Artificial Intelligence Research. The output is a list of recently published AI papers. You’ll use Cohere’s Embed Endpoint to generate word embeddings using your list of AI papers. Finally, visualize the embeddings and proceed to build semantic search and topic modeling.
+
To follow along with this tutorial, you need to be familiar with Python. Make sure you have python version 3.6+ installed in your development machine. You can also use Google Colab to try out the project in the cloud. Finally, you need to have a Cohere Account. If you haven’t signed up already, register for a New Cohere Account. All new accounts receive $75 free credits. You'll access a Pay-As-You-Go option after finishing your credits.
+# **Getting Started**
+
First, you need to install the python dependencies required to run the project. Use pip to install them using the command below
-```python PYTHON
+
+```python
pip install requests beautifulsoup4 cohere altair clean-text numpy pandas sklearn > /dev/null
```
Create a new python file named cohere_nlp.py. Write all your code in this file. import the dependencies and initialize Cohere’s client.
-```python PYTHON
+
+```python
import cohere
-api_key = ''
+# Paste your API key here. Remember to not share it publicly
+api_key = '
+
+
+
+# Semantic Search
Data searching techniques focus on using keywords to retrieve text-based information. You can take this a level higher. Use search queries to determine the intent and contextual meaning. In this section, you’ll use Cohere to create embeddings for the search query. Use the embeddings to get the similarity with your dataset’s embeddings. The output is a list of similar AI papers.
First, create a function to get similarities between two embeddings. This will use the cosine similarity algorithm from the sci-kit learn library.
-```python PYTHON
+
+
+```python
from sklearn.metrics.pairwise import cosine_similarity
def get_similarity(target,candidates):
@@ -273,18 +312,24 @@ def get_similarity(target,candidates):
Next, create embeddings for the search query
-```python PYTHON
+
+```python
+# Add new query
new_query = "graph network strategies"
+# Get embeddings of the new query
new_query_embeds = get_embeddings(new_query)
```
Finally, check the similarity between the two embeddings. Display the top 10 similar papers using your result
-```python PYTHON
+
+```python
+# Get the similarity between the search query and existing queries
similarity = get_similarity(new_query_embeds,embeds[:sample])
+# View the top 5 articles
print('Query:')
print(new_query,'\n')
@@ -294,222 +339,225 @@ for idx,sim in similarity:
```
-```
-Query:
-graph network strategies
-
-Similar queries:
-Similarity: 0.49; amp chain graphs: minimal separators and structure learning algorithms
-Similarity: 0.46; pure nash equilibria in resource graph games
-Similarity: 0.44; general value function networks
-Similarity: 0.42; on the online coalition structure generation problem
-Similarity: 0.42; efficient local search based on dynamic connectivity maintenance for minimum connected dominating set
-Similarity: 0.42; graph kernels: a survey
-Similarity: 0.39; rwne: a scalable random-walk based network embedding framework with personalized higher-order proximity preserved
-Similarity: 0.39; the petlon algorithm to plan efficiently for task-level-optimal navigation
-Similarity: 0.38; election manipulation on social networks: seeding, edge removal, edge addition
-Similarity: 0.38; a semi-exact algorithm for quickly computing a maximum weight clique in large sparse graphs
-Similarity: 0.37; probabilistic temporal networks with ordinary distributions: theory, robustness and expected utility
-Similarity: 0.36; adaptive greedy versus non-adaptive greedy for influence maximization
-Similarity: 0.35; classifier chains: a review and perspectives
-Similarity: 0.35; learning bayesian networks under sparsity constraints: a parameterized complexity analysis
-Similarity: 0.34; optimally deceiving a learning leader in stackelberg games
-Similarity: 0.34; planning high-level paths in hostile, dynamic, and uncertain environments
-Similarity: 0.34; computational complexity of computing symmetries in finite-domain planning
-Similarity: 0.33; on the indecisiveness of kelly-strategyproof social choice functions
-Similarity: 0.33; qualitative numeric planning: reductions and complexity
-Similarity: 0.33; intelligence in strategic games
-Similarity: 0.33; steady-state planning in expected reward multichain mdps
-Similarity: 0.32; hybrid-order network consensus for distributed multi-agent systems
-Similarity: 0.32; evaluating strategic structures in multi-agent inverse reinforcement learning
-Similarity: 0.32; multi-agent advisor q-learning
-Similarity: 0.32; fairness in influence maximization through randomization
-Similarity: 0.32; a sufficient statistic for influence in structured multiagent environments
-Similarity: 0.32; constraint and satisfiability reasoning for graph coloring
-Similarity: 0.31; sum-of-products with default values: algorithms and complexity results
-Similarity: 0.31; contrastive explanations of plans through model restrictions
-Similarity: 0.31; zone path construction (zac) based approaches for effective real-time ridesharing
-Similarity: 0.31; an external knowledge enhanced graph-based neural network for sentence ordering
-Similarity: 0.31; finding and recognizing popular coalition structures
-Similarity: 0.30; constraint-based diversification of jop gadgets
-Similarity: 0.30; improved high dimensional discrete bayesian network inference using triplet region construction
-Similarity: 0.30; migrating techniques from search-based multi-agent path finding solvers to sat-based approach
-Similarity: 0.30; proactive dynamic distributed constraint optimization problems
-Similarity: 0.30; safe multi-agent pathfinding with time uncertainty
-Similarity: 0.30; a logic-based explanation generation framework for classical and hybrid planning problems
-Similarity: 0.30; scalable online planning for multi-agent mdps
-Similarity: 0.30; on sparse discretization for graphical games
-Similarity: 0.30; fond planning with explicit fairness assumptions
-Similarity: 0.29; jointly learning environments and control policies with projected stochastic gradient ascent
-Similarity: 0.29; computational benefits of intermediate rewards for goal-reaching policy learning
-Similarity: 0.29; two-phase multi-document event summarization on core event graphs
-Similarity: 0.29; efficient large-scale multi-drone delivery using transit networks
-Similarity: 0.29; fast adaptive non-monotone submodular maximization subject to a knapsack constraint
-Similarity: 0.29; path counting for grid-based navigation
-Similarity: 0.29; preferences single-peaked on a tree: multiwinner elections and structural results
-Similarity: 0.29; merge-and-shrink: a compositional theory of transformations of factored transition systems
-Similarity: 0.29; lilotane: a lifted sat-based approach to hierarchical planning
-Similarity: 0.29; cost-optimal planning, delete relaxation, approximability, and heuristics
-Similarity: 0.29; learning over no-preferred and preferred sequence of items for robust recommendation
-Similarity: 0.28; a few queries go a long way: information-distortion tradeoffs in matching
-Similarity: 0.28; constrained multiagent markov decision processes: a taxonomy of problems and algorithms
-Similarity: 0.28; contiguous cake cutting: hardness results and approximation algorithms
-Similarity: 0.28; online relaxation refinement for satisficing planning: on partial delete relaxation, complete hill-climbing, and novelty pruning
-Similarity: 0.28; playing codenames with language graphs and word embeddings
-Similarity: 0.28; a theoretical perspective on hyperdimensional computing
-Similarity: 0.28; reasoning with pcp-nets
-Similarity: 0.28; improving the effectiveness and efficiency of stochastic neighbour embedding with isolation kernel
-Similarity: 0.27; teaching people by justifying tree search decisions: an empirical study in curling
-Similarity: 0.27; learning optimal decision sets and lists with sat
-Similarity: 0.27; efficient multi-objective reinforcement learning via multiple-gradient descent with iteratively discovered weight-vector sets
-Similarity: 0.27; liquid democracy: an algorithmic perspective
-Similarity: 0.27; contrasting the spread of misinformation in online social networks
-Similarity: 0.27; on the computational complexity of non-dictatorial aggregation
-Similarity: 0.27; planning with critical section macros: theory and practice
-Similarity: 0.27; regarding goal bounding and jump point search
-Similarity: 0.27; using machine learning for decreasing state uncertainty in planning
-Similarity: 0.26; strategyproof mechanisms for additively separable and fractional hedonic games
-Similarity: 0.26; ranking sets of objects: the complexity of avoiding impossibility results
-Similarity: 0.26; socially responsible ai algorithms: issues, purposes, and challenges
-Similarity: 0.26; inductive logic programming at 30: a new introduction
-Similarity: 0.26; to regulate or not: a social dynamics analysis of an idealised ai race
-Similarity: 0.25; learning temporal causal sequence relationships from real-time time-series
-Similarity: 0.25; integrated offline and online decision making under uncertainty
-Similarity: 0.25; the computational complexity of understanding binary classifier decisions
-Similarity: 0.25; a survey of opponent modeling in adversarial domains
-Similarity: 0.25; cooperation and learning dynamics under wealth inequality and diversity in individual risk
-Similarity: 0.25; sunny-as2: enhancing sunny for algorithm selection
-Similarity: 0.25; game plan: what ai can do for football, and what football can do for ai
-Similarity: 0.25; approximating perfect recall when model checking strategic abilities: theory and applications
-Similarity: 0.25; efficient retrieval of matrix factorization-based top-k recommendations: a survey of recent approaches
-Similarity: 0.25; evolutionary dynamics and phi-regret minimization in games
-Similarity: 0.24; labeled bipolar argumentation frameworks
-Similarity: 0.24; optimal any-angle pathfinding on a sphere
-Similarity: 0.24; learning from disagreement: a survey
-Similarity: 0.24; on the cluster admission problem for cloud computing
-Similarity: 0.24; aggregation over metric spaces: proposing and voting in elections, budgeting, and legislation
-Similarity: 0.24; ordinal maximin share approximation for goods
-Similarity: 0.24; constraint solving approaches to the business-to-business meeting scheduling problem
-Similarity: 0.24; objective bayesian nets for integrating consistent datasets
-Similarity: 0.24; quantum mathematics in artificial intelligence
-Similarity: 0.24; task-aware verifiable rnn-based policies for partially observable markov decision processes
-Similarity: 0.23; samba: a generic framework for secure federated multi-armed bandits
-Similarity: 0.23; automated reinforcement learning (autorl): a survey and open problems
-Similarity: 0.23; generic constraint-based block modeling using constraint programming
-Similarity: 0.23; a comprehensive framework for learning declarative action models
-Similarity: 0.23; optimizing for interpretability in deep neural networks with tree regularization
-Similarity: 0.22; impact of imputation strategies on fairness in machine learning
-Similarity: 0.22; set-to-sequence methods in machine learning: a review
-Similarity: 0.22; the ai liability puzzle and a fund-based work-around
-Similarity: 0.22; agent-based markov modeling for improved covid-19 mitigation policies
-Similarity: 0.22; the parameterized complexity of motion planning for snake-like robots
-Similarity: 0.22; induction and exploitation of subgoal automata for reinforcement learning
-Similarity: 0.22; point at the triple: generation of text summaries from knowledge base triples
-Similarity: 0.22; trends in integration of vision and language research: a survey of tasks, datasets, and methods
-Similarity: 0.21; multi-document summarization with determinantal point process attention
-Similarity: 0.21; reward machines: exploiting reward function structure in reinforcement learning
-Similarity: 0.21; computing bayes-nash equilibria in combinatorial auctions with verification
-Similarity: 0.21; taking principles seriously: a hybrid approach to value alignment in artificial intelligence
-Similarity: 0.21; two-facility location games with minimum distance requirement
-Similarity: 0.21; structure from randomness in halfspace learning with the zero-one loss
-Similarity: 0.21; avoiding negative side effects of autonomous systems in the open world
-Similarity: 0.21; learning realistic patterns from visually unrealistic stimuli: generalization and data anonymization
-Similarity: 0.21; properties of switch-list representations of boolean functions
-Similarity: 0.21; conceptual modeling of explainable recommender systems: an ontological formalization to guide their design and development
-Similarity: 0.21; predicting decisions in language based persuasion games
-Similarity: 0.20; epidemioptim: a toolbox for the optimization of control policies in epidemiological models
-Similarity: 0.20; ffci: a framework for interpretable automatic evaluation of summarization
-Similarity: 0.20; analysis of the impact of randomization of search-control parameters in monte-carlo tree search
-Similarity: 0.20; output space entropy search framework for multi-objective bayesian optimization
-Similarity: 0.20; multiobjective tree-structured parzen estimator
-Similarity: 0.19; on the decomposition of abstract dialectical frameworks and the complexity of naive-based semantics
-Similarity: 0.19; hebo: pushing the limits of sample-efficient hyper-parameter optimisation
-Similarity: 0.19; superintelligence cannot be contained: lessons from computability theory
-Similarity: 0.19; goal recognition for deceptive human agents through planning and gaze
-Similarity: 0.19; dimensional inconsistency measures and postulates in spatio-temporal databases
-Similarity: 0.19; explainable deep learning: a field guide for the uninitiated
-Similarity: 0.19; multi-label classification neural networks with hard logical constraints
-Similarity: 0.19; declarative algorithms and complexity results for assumption-based argumentation
-Similarity: 0.19; worst-case bounds on power vs. proportion in weighted voting games with an application to false-name manipulation
-Similarity: 0.19; collie: continual learning of language grounding from language-image embeddings
-Similarity: 0.18; a word selection method for producing interpretable distributional semantic word vectors
-Similarity: 0.18; the bottleneck simulator: a model-based deep reinforcement learning approach
-Similarity: 0.18; metric-distortion bounds under limited information
-Similarity: 0.18; neural natural language generation: a survey on multilinguality, multimodality, controllability and learning
-Similarity: 0.18; on the evolvability of monotone conjunctions with an evolutionary mutation mechanism
-Similarity: 0.18; a metric space for point process excitations
-Similarity: 0.18; autotelic agents with intrinsically motivated goal-conditioned reinforcement learning: a short survey
-Similarity: 0.18; the application of machine learning techniques for predicting match results in team sport: a review
-Similarity: 0.18; incremental event calculus for run-time reasoning
-Similarity: 0.18; a survey on the explainability of supervised machine learning
-Similarity: 0.18; madras : multi agent driving simulator
-Similarity: 0.17; maximin share allocations on cycles
-Similarity: 0.17; the rediscovery hypothesis: language models need to meet linguistics
-Similarity: 0.17; some inapproximability results of map inference and exponentiated determinantal point processes
-Similarity: 0.17; visually grounded models of spoken language: a survey of datasets, architectures and evaluation techniques
-Similarity: 0.17; the complexity landscape of outcome determination in judgment aggregation
-Similarity: 0.17; survey and evaluation of causal discovery methods for time series
-Similarity: 0.17; agent-based modeling for predicting pedestrian trajectories around an autonomous vehicle
-Similarity: 0.16; rethinking fairness: an interdisciplinary survey of critiques of hegemonic ml fairness approaches
-Similarity: 0.16; mapping the landscape of artificial intelligence applications against covid-19
-Similarity: 0.16; crossing the conversational chasm: a primer on natural language processing for multilingual task-oriented dialogue systems
-Similarity: 0.16; neural machine translation: a review
-Similarity: 0.16; viewpoint: ethical by designer - how to grow ethical designers of artificial intelligence
-Similarity: 0.16; core challenges in embodied vision-language planning
-Similarity: 0.16; neural character-level syntactic parsing for chinese
-Similarity: 0.16; marginal distance and hilbert-schmidt covariances-based independence tests for multivariate functional data
-Similarity: 0.16; instance-level update in dl-lite ontologies through first-order rewriting
-Similarity: 0.16; the societal implications of deep reinforcement learning
-Similarity: 0.16; benchmark and survey of automated machine learning frameworks
-Similarity: 0.16; experimental comparison and survey of twelve time series anomaly detection algorithms
-Similarity: 0.15; annotator rationales for labeling tasks in crowdsourcing
-Similarity: 0.15; representative committees of peers
-Similarity: 0.15; fine-grained prediction of political leaning on social media with unsupervised deep learning
-Similarity: 0.15; out of context: a new clue for context modeling of aspect-based sentiment analysis
-Similarity: 0.15; loss functions, axioms, and peer review
-Similarity: 0.15; on the tractability of shap explanations
-Similarity: 0.15; doubly robust crowdsourcing
-Similarity: 0.15; adversarial framework with certified robustness for time-series domain via statistical features
-Similarity: 0.14; on quantifying literals in boolean logic and its applications to explainable ai
-Similarity: 0.14; bribery and control in stable marriage
-Similarity: 0.14; finding the hardest formulas for resolution
-Similarity: 0.14; supervised visual attention for simultaneous multimodal machine translation
-Similarity: 0.14; a tight bound for stochastic submodular cover
-Similarity: 0.14; ethics and governance of artificial intelligence: evidence from a survey of machine learning researchers
-Similarity: 0.13; flexible bayesian nonlinear model configuration
-Similarity: 0.13; multilingual machine translation: deep analysis of language-specific encoder-decoders
-Similarity: 0.13; multilabel classification with partial abstention: bayes-optimal prediction under label independence
-Similarity: 0.13; viewpoint: ai as author bridging the gap between machine learning and literary theory
-Similarity: 0.13; confident learning: estimating uncertainty in dataset labels
-Similarity: 0.13; belief change and 3-valued logics: characterization of 19,683 belief change operators
-Similarity: 0.13; get out of the bag! silos in ai ethics education: unsupervised topic modeling analysis of global ai curricula
-Similarity: 0.12; on the distortion value of elections with abstention
-Similarity: 0.12; measuring the occupational impact of ai: tasks, cognitive abilities and ai benchmarks
-Similarity: 0.11; fair division of indivisible goods for a class of concave valuations
-Similarity: 0.10; admissibility in probabilistic argumentation
-Similarity: 0.10; recursion in abstract argumentation is hard --- on the complexity of semantics based on weak admissibility
-Similarity: 0.10; weighted first-order model counting in the two-variable fragment with counting quantifiers
-Similarity: 0.10; incompatibilities between iterated and relevance-sensitive belief revision
-Similarity: 0.10; automatic recognition of the general-purpose communicative functions defined by the iso 24617-2 standard for dialog act annotation
-Similarity: 0.09; nlp methods for extraction of symptoms from unstructured data for use in prognostic covid-19 analytic models
-Similarity: 0.09; welfare guarantees in schelling segregation
-Similarity: 0.09; casa: conversational aspect sentiment analysis for dialogue understanding
-Similarity: 0.09; a survey of algorithms for black-box safety validation of cyber-physical systems
-Similarity: 0.07; relevance in belief update
-Similarity: 0.06; on super strong eth
-Similarity: 0.06; image captioning as an assistive technology: lessons learned from vizwiz 2020 challenge
-Similarity: 0.03; confronting abusive language online: a survey from the ethical and human rights perspective
-```
+ Query:
+ graph network strategies
+
+ Similar queries:
+ Similarity: 0.49; amp chain graphs: minimal separators and structure learning algorithms
+ Similarity: 0.46; pure nash equilibria in resource graph games
+ Similarity: 0.44; general value function networks
+ Similarity: 0.42; on the online coalition structure generation problem
+ Similarity: 0.42; efficient local search based on dynamic connectivity maintenance for minimum connected dominating set
+ Similarity: 0.42; graph kernels: a survey
+ Similarity: 0.39; rwne: a scalable random-walk based network embedding framework with personalized higher-order proximity preserved
+ Similarity: 0.39; the petlon algorithm to plan efficiently for task-level-optimal navigation
+ Similarity: 0.38; election manipulation on social networks: seeding, edge removal, edge addition
+ Similarity: 0.38; a semi-exact algorithm for quickly computing a maximum weight clique in large sparse graphs
+ Similarity: 0.37; probabilistic temporal networks with ordinary distributions: theory, robustness and expected utility
+ Similarity: 0.36; adaptive greedy versus non-adaptive greedy for influence maximization
+ Similarity: 0.35; classifier chains: a review and perspectives
+ Similarity: 0.35; learning bayesian networks under sparsity constraints: a parameterized complexity analysis
+ Similarity: 0.34; optimally deceiving a learning leader in stackelberg games
+ Similarity: 0.34; planning high-level paths in hostile, dynamic, and uncertain environments
+ Similarity: 0.34; computational complexity of computing symmetries in finite-domain planning
+ Similarity: 0.33; on the indecisiveness of kelly-strategyproof social choice functions
+ Similarity: 0.33; qualitative numeric planning: reductions and complexity
+ Similarity: 0.33; intelligence in strategic games
+ Similarity: 0.33; steady-state planning in expected reward multichain mdps
+ Similarity: 0.32; hybrid-order network consensus for distributed multi-agent systems
+ Similarity: 0.32; evaluating strategic structures in multi-agent inverse reinforcement learning
+ Similarity: 0.32; multi-agent advisor q-learning
+ Similarity: 0.32; fairness in influence maximization through randomization
+ Similarity: 0.32; a sufficient statistic for influence in structured multiagent environments
+ Similarity: 0.32; constraint and satisfiability reasoning for graph coloring
+ Similarity: 0.31; sum-of-products with default values: algorithms and complexity results
+ Similarity: 0.31; contrastive explanations of plans through model restrictions
+ Similarity: 0.31; zone path construction (zac) based approaches for effective real-time ridesharing
+ Similarity: 0.31; an external knowledge enhanced graph-based neural network for sentence ordering
+ Similarity: 0.31; finding and recognizing popular coalition structures
+ Similarity: 0.30; constraint-based diversification of jop gadgets
+ Similarity: 0.30; improved high dimensional discrete bayesian network inference using triplet region construction
+ Similarity: 0.30; migrating techniques from search-based multi-agent path finding solvers to sat-based approach
+ Similarity: 0.30; proactive dynamic distributed constraint optimization problems
+ Similarity: 0.30; safe multi-agent pathfinding with time uncertainty
+ Similarity: 0.30; a logic-based explanation generation framework for classical and hybrid planning problems
+ Similarity: 0.30; scalable online planning for multi-agent mdps
+ Similarity: 0.30; on sparse discretization for graphical games
+ Similarity: 0.30; fond planning with explicit fairness assumptions
+ Similarity: 0.29; jointly learning environments and control policies with projected stochastic gradient ascent
+ Similarity: 0.29; computational benefits of intermediate rewards for goal-reaching policy learning
+ Similarity: 0.29; two-phase multi-document event summarization on core event graphs
+ Similarity: 0.29; efficient large-scale multi-drone delivery using transit networks
+ Similarity: 0.29; fast adaptive non-monotone submodular maximization subject to a knapsack constraint
+ Similarity: 0.29; path counting for grid-based navigation
+ Similarity: 0.29; preferences single-peaked on a tree: multiwinner elections and structural results
+ Similarity: 0.29; merge-and-shrink: a compositional theory of transformations of factored transition systems
+ Similarity: 0.29; lilotane: a lifted sat-based approach to hierarchical planning
+ Similarity: 0.29; cost-optimal planning, delete relaxation, approximability, and heuristics
+ Similarity: 0.29; learning over no-preferred and preferred sequence of items for robust recommendation
+ Similarity: 0.28; a few queries go a long way: information-distortion tradeoffs in matching
+ Similarity: 0.28; constrained multiagent markov decision processes: a taxonomy of problems and algorithms
+ Similarity: 0.28; contiguous cake cutting: hardness results and approximation algorithms
+ Similarity: 0.28; online relaxation refinement for satisficing planning: on partial delete relaxation, complete hill-climbing, and novelty pruning
+ Similarity: 0.28; playing codenames with language graphs and word embeddings
+ Similarity: 0.28; a theoretical perspective on hyperdimensional computing
+ Similarity: 0.28; reasoning with pcp-nets
+ Similarity: 0.28; improving the effectiveness and efficiency of stochastic neighbour embedding with isolation kernel
+ Similarity: 0.27; teaching people by justifying tree search decisions: an empirical study in curling
+ Similarity: 0.27; learning optimal decision sets and lists with sat
+ Similarity: 0.27; efficient multi-objective reinforcement learning via multiple-gradient descent with iteratively discovered weight-vector sets
+ Similarity: 0.27; liquid democracy: an algorithmic perspective
+ Similarity: 0.27; contrasting the spread of misinformation in online social networks
+ Similarity: 0.27; on the computational complexity of non-dictatorial aggregation
+ Similarity: 0.27; planning with critical section macros: theory and practice
+ Similarity: 0.27; regarding goal bounding and jump point search
+ Similarity: 0.27; using machine learning for decreasing state uncertainty in planning
+ Similarity: 0.26; strategyproof mechanisms for additively separable and fractional hedonic games
+ Similarity: 0.26; ranking sets of objects: the complexity of avoiding impossibility results
+ Similarity: 0.26; socially responsible ai algorithms: issues, purposes, and challenges
+ Similarity: 0.26; inductive logic programming at 30: a new introduction
+ Similarity: 0.26; to regulate or not: a social dynamics analysis of an idealised ai race
+ Similarity: 0.25; learning temporal causal sequence relationships from real-time time-series
+ Similarity: 0.25; integrated offline and online decision making under uncertainty
+ Similarity: 0.25; the computational complexity of understanding binary classifier decisions
+ Similarity: 0.25; a survey of opponent modeling in adversarial domains
+ Similarity: 0.25; cooperation and learning dynamics under wealth inequality and diversity in individual risk
+ Similarity: 0.25; sunny-as2: enhancing sunny for algorithm selection
+ Similarity: 0.25; game plan: what ai can do for football, and what football can do for ai
+ Similarity: 0.25; approximating perfect recall when model checking strategic abilities: theory and applications
+ Similarity: 0.25; efficient retrieval of matrix factorization-based top-k recommendations: a survey of recent approaches
+ Similarity: 0.25; evolutionary dynamics and phi-regret minimization in games
+ Similarity: 0.24; labeled bipolar argumentation frameworks
+ Similarity: 0.24; optimal any-angle pathfinding on a sphere
+ Similarity: 0.24; learning from disagreement: a survey
+ Similarity: 0.24; on the cluster admission problem for cloud computing
+ Similarity: 0.24; aggregation over metric spaces: proposing and voting in elections, budgeting, and legislation
+ Similarity: 0.24; ordinal maximin share approximation for goods
+ Similarity: 0.24; constraint solving approaches to the business-to-business meeting scheduling problem
+ Similarity: 0.24; objective bayesian nets for integrating consistent datasets
+ Similarity: 0.24; quantum mathematics in artificial intelligence
+ Similarity: 0.24; task-aware verifiable rnn-based policies for partially observable markov decision processes
+ Similarity: 0.23; samba: a generic framework for secure federated multi-armed bandits
+ Similarity: 0.23; automated reinforcement learning (autorl): a survey and open problems
+ Similarity: 0.23; generic constraint-based block modeling using constraint programming
+ Similarity: 0.23; a comprehensive framework for learning declarative action models
+ Similarity: 0.23; optimizing for interpretability in deep neural networks with tree regularization
+ Similarity: 0.22; impact of imputation strategies on fairness in machine learning
+ Similarity: 0.22; set-to-sequence methods in machine learning: a review
+ Similarity: 0.22; the ai liability puzzle and a fund-based work-around
+ Similarity: 0.22; agent-based markov modeling for improved covid-19 mitigation policies
+ Similarity: 0.22; the parameterized complexity of motion planning for snake-like robots
+ Similarity: 0.22; induction and exploitation of subgoal automata for reinforcement learning
+ Similarity: 0.22; point at the triple: generation of text summaries from knowledge base triples
+ Similarity: 0.22; trends in integration of vision and language research: a survey of tasks, datasets, and methods
+ Similarity: 0.21; multi-document summarization with determinantal point process attention
+ Similarity: 0.21; reward machines: exploiting reward function structure in reinforcement learning
+ Similarity: 0.21; computing bayes-nash equilibria in combinatorial auctions with verification
+ Similarity: 0.21; taking principles seriously: a hybrid approach to value alignment in artificial intelligence
+ Similarity: 0.21; two-facility location games with minimum distance requirement
+ Similarity: 0.21; structure from randomness in halfspace learning with the zero-one loss
+ Similarity: 0.21; avoiding negative side effects of autonomous systems in the open world
+ Similarity: 0.21; learning realistic patterns from visually unrealistic stimuli: generalization and data anonymization
+ Similarity: 0.21; properties of switch-list representations of boolean functions
+ Similarity: 0.21; conceptual modeling of explainable recommender systems: an ontological formalization to guide their design and development
+ Similarity: 0.21; predicting decisions in language based persuasion games
+ Similarity: 0.20; epidemioptim: a toolbox for the optimization of control policies in epidemiological models
+ Similarity: 0.20; ffci: a framework for interpretable automatic evaluation of summarization
+ Similarity: 0.20; analysis of the impact of randomization of search-control parameters in monte-carlo tree search
+ Similarity: 0.20; output space entropy search framework for multi-objective bayesian optimization
+ Similarity: 0.20; multiobjective tree-structured parzen estimator
+ Similarity: 0.19; on the decomposition of abstract dialectical frameworks and the complexity of naive-based semantics
+ Similarity: 0.19; hebo: pushing the limits of sample-efficient hyper-parameter optimisation
+ Similarity: 0.19; superintelligence cannot be contained: lessons from computability theory
+ Similarity: 0.19; goal recognition for deceptive human agents through planning and gaze
+ Similarity: 0.19; dimensional inconsistency measures and postulates in spatio-temporal databases
+ Similarity: 0.19; explainable deep learning: a field guide for the uninitiated
+ Similarity: 0.19; multi-label classification neural networks with hard logical constraints
+ Similarity: 0.19; declarative algorithms and complexity results for assumption-based argumentation
+ Similarity: 0.19; worst-case bounds on power vs. proportion in weighted voting games with an application to false-name manipulation
+ Similarity: 0.19; collie: continual learning of language grounding from language-image embeddings
+ Similarity: 0.18; a word selection method for producing interpretable distributional semantic word vectors
+ Similarity: 0.18; the bottleneck simulator: a model-based deep reinforcement learning approach
+ Similarity: 0.18; metric-distortion bounds under limited information
+ Similarity: 0.18; neural natural language generation: a survey on multilinguality, multimodality, controllability and learning
+ Similarity: 0.18; on the evolvability of monotone conjunctions with an evolutionary mutation mechanism
+ Similarity: 0.18; a metric space for point process excitations
+ Similarity: 0.18; autotelic agents with intrinsically motivated goal-conditioned reinforcement learning: a short survey
+ Similarity: 0.18; the application of machine learning techniques for predicting match results in team sport: a review
+ Similarity: 0.18; incremental event calculus for run-time reasoning
+ Similarity: 0.18; a survey on the explainability of supervised machine learning
+ Similarity: 0.18; madras : multi agent driving simulator
+ Similarity: 0.17; maximin share allocations on cycles
+ Similarity: 0.17; the rediscovery hypothesis: language models need to meet linguistics
+ Similarity: 0.17; some inapproximability results of map inference and exponentiated determinantal point processes
+ Similarity: 0.17; visually grounded models of spoken language: a survey of datasets, architectures and evaluation techniques
+ Similarity: 0.17; the complexity landscape of outcome determination in judgment aggregation
+ Similarity: 0.17; survey and evaluation of causal discovery methods for time series
+ Similarity: 0.17; agent-based modeling for predicting pedestrian trajectories around an autonomous vehicle
+ Similarity: 0.16; rethinking fairness: an interdisciplinary survey of critiques of hegemonic ml fairness approaches
+ Similarity: 0.16; mapping the landscape of artificial intelligence applications against covid-19
+ Similarity: 0.16; crossing the conversational chasm: a primer on natural language processing for multilingual task-oriented dialogue systems
+ Similarity: 0.16; neural machine translation: a review
+ Similarity: 0.16; viewpoint: ethical by designer - how to grow ethical designers of artificial intelligence
+ Similarity: 0.16; core challenges in embodied vision-language planning
+ Similarity: 0.16; neural character-level syntactic parsing for chinese
+ Similarity: 0.16; marginal distance and hilbert-schmidt covariances-based independence tests for multivariate functional data
+ Similarity: 0.16; instance-level update in dl-lite ontologies through first-order rewriting
+ Similarity: 0.16; the societal implications of deep reinforcement learning
+ Similarity: 0.16; benchmark and survey of automated machine learning frameworks
+ Similarity: 0.16; experimental comparison and survey of twelve time series anomaly detection algorithms
+ Similarity: 0.15; annotator rationales for labeling tasks in crowdsourcing
+ Similarity: 0.15; representative committees of peers
+ Similarity: 0.15; fine-grained prediction of political leaning on social media with unsupervised deep learning
+ Similarity: 0.15; out of context: a new clue for context modeling of aspect-based sentiment analysis
+ Similarity: 0.15; loss functions, axioms, and peer review
+ Similarity: 0.15; on the tractability of shap explanations
+ Similarity: 0.15; doubly robust crowdsourcing
+ Similarity: 0.15; adversarial framework with certified robustness for time-series domain via statistical features
+ Similarity: 0.14; on quantifying literals in boolean logic and its applications to explainable ai
+ Similarity: 0.14; bribery and control in stable marriage
+ Similarity: 0.14; finding the hardest formulas for resolution
+ Similarity: 0.14; supervised visual attention for simultaneous multimodal machine translation
+ Similarity: 0.14; a tight bound for stochastic submodular cover
+ Similarity: 0.14; ethics and governance of artificial intelligence: evidence from a survey of machine learning researchers
+ Similarity: 0.13; flexible bayesian nonlinear model configuration
+ Similarity: 0.13; multilingual machine translation: deep analysis of language-specific encoder-decoders
+ Similarity: 0.13; multilabel classification with partial abstention: bayes-optimal prediction under label independence
+ Similarity: 0.13; viewpoint: ai as author bridging the gap between machine learning and literary theory
+ Similarity: 0.13; confident learning: estimating uncertainty in dataset labels
+ Similarity: 0.13; belief change and 3-valued logics: characterization of 19,683 belief change operators
+ Similarity: 0.13; get out of the bag! silos in ai ethics education: unsupervised topic modeling analysis of global ai curricula
+ Similarity: 0.12; on the distortion value of elections with abstention
+ Similarity: 0.12; measuring the occupational impact of ai: tasks, cognitive abilities and ai benchmarks
+ Similarity: 0.11; fair division of indivisible goods for a class of concave valuations
+ Similarity: 0.10; admissibility in probabilistic argumentation
+ Similarity: 0.10; recursion in abstract argumentation is hard --- on the complexity of semantics based on weak admissibility
+ Similarity: 0.10; weighted first-order model counting in the two-variable fragment with counting quantifiers
+ Similarity: 0.10; incompatibilities between iterated and relevance-sensitive belief revision
+ Similarity: 0.10; automatic recognition of the general-purpose communicative functions defined by the iso 24617-2 standard for dialog act annotation
+ Similarity: 0.09; nlp methods for extraction of symptoms from unstructured data for use in prognostic covid-19 analytic models
+ Similarity: 0.09; welfare guarantees in schelling segregation
+ Similarity: 0.09; casa: conversational aspect sentiment analysis for dialogue understanding
+ Similarity: 0.09; a survey of algorithms for black-box safety validation of cyber-physical systems
+ Similarity: 0.07; relevance in belief update
+ Similarity: 0.06; on super strong eth
+ Similarity: 0.06; image captioning as an assistive technology: lessons learned from vizwiz 2020 challenge
+ Similarity: 0.03; confronting abusive language online: a survey from the ethical and human rights perspective
+
Visualizing semantic search: https://github.com/cohere-ai/cohere-developer-experience/blob/main/notebooks/Visualizing_Text_Embeddings.ipynb
-Clustering is a process of grouping similar documents into clusters. It allows you to organize many documents into a smaller number of groups. As a result, you can discover emerging patterns in the documents. In this section, you will use the k-Means clustering algorithm to identify the top 5 clusters.
+# Text Clustering
+Clustering is a process of grouping similar documents into clusters. It allows you to organize many documents into a smaller number of groups. As a result, you can discover emerging patterns in the documents. In this section, you will use the k-Means clustering algorithm to identify the top 5 clusters.
First, import the k-means algorithm from the scikit-learn package. Then configure two variables: the number of clusters and a duplicate dataset.
-```python PYTHON
+
+
+```python
from sklearn.cluster import KMeans
+# Pick the number of clusters
df_clust = df_pc2.copy()
n_clusters=5
@@ -517,7 +565,9 @@ n_clusters=5
Next, initialize the k-means model and use it to fit the embeddings to create the clusters.
-```python PYTHON
+
+```python
+# Cluster the embeddings
kmeans_model = KMeans(n_clusters=n_clusters, random_state=0)
classes = kmeans_model.fit_predict(embeds).tolist()
print(classes)
@@ -525,17 +575,29 @@ df_clust['cluster'] = (list(map(str,classes)))
```
-```
-[2, 0, 3, 4, 4, 3, 1, 1, 0, 3, 0, 2, 0, 1, 1, 0, 0, 2, 0, 1, 3, 2, 1, 3, 0, 2, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 1, 1, 2, 2, 2, 4, 3, 3, 3, 3, 2, 1, 2, 4, 3, 0, 2, 0, 1, 1, 0, 4, 0, 2, 2, 3, 1, 2, 4, 1, 2, 1, 4, 0, 3, 3, 4, 2, 0, 2, 2, 2, 0, 0, 0, 4, 1, 4, 1, 2, 0, 4, 1, 1, 4, 1, 4, 1, 4, 1, 0, 0, 4, 2, 4, 3, 4, 3, 2, 0, 2, 1, 1, 4, 2, 4, 2, 2, 0, 3, 1, 3, 2, 3, 1, 2, 0, 4, 4, 1, 0, 0, 4, 1, 1, 2, 2, 1, 2, 3, 0, 0, 1, 1, 1, 0, 4, 1, 4, 2, 4, 2, 4, 3, 2, 0, 1, 4, 1, 1, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 2, 0, 2, 0, 4, 2, 4, 2, 1, 0, 3, 0, 1, 0, 2, 2, 1, 4, 1, 3, 4, 1, 0, 2, 1, 2, 0, 2, 4, 1, 4, 2, 2, 1, 0, 0, 1, 0, 2, 1, 0, 4, 1, 4, 0, 2, 1, 4, 1, 3, 2, 4, 2, 0, 1, 0, 3, 0, 2, 4, 1, 1, 3, 2, 3, 1, 3, 4, 2, 2, 0, 1, 1, 1, 4, 1, 0, 4, 3, 2, 2, 2, 2, 0, 1, 3, 1, 3, 4, 2, 4, 2, 1, 3]
-```
+ [2, 0, 3, 4, 4, 3, 1, 1, 0, 3, 0, 2, 0, 1, 1, 0, 0, 2, 0, 1, 3, 2, 1, 3, 0, 2, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 1, 1, 2, 2, 2, 4, 3, 3, 3, 3, 2, 1, 2, 4, 3, 0, 2, 0, 1, 1, 0, 4, 0, 2, 2, 3, 1, 2, 4, 1, 2, 1, 4, 0, 3, 3, 4, 2, 0, 2, 2, 2, 0, 0, 0, 4, 1, 4, 1, 2, 0, 4, 1, 1, 4, 1, 4, 1, 4, 1, 0, 0, 4, 2, 4, 3, 4, 3, 2, 0, 2, 1, 1, 4, 2, 4, 2, 2, 0, 3, 1, 3, 2, 3, 1, 2, 0, 4, 4, 1, 0, 0, 4, 1, 1, 2, 2, 1, 2, 3, 0, 0, 1, 1, 1, 0, 4, 1, 4, 2, 4, 2, 4, 3, 2, 0, 1, 4, 1, 1, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 2, 0, 2, 0, 4, 2, 4, 2, 1, 0, 3, 0, 1, 0, 2, 2, 1, 4, 1, 3, 4, 1, 0, 2, 1, 2, 0, 2, 4, 1, 4, 2, 2, 1, 0, 0, 1, 0, 2, 1, 0, 4, 1, 4, 0, 2, 1, 4, 1, 3, 2, 4, 2, 0, 1, 0, 3, 0, 2, 4, 1, 1, 3, 2, 3, 1, 3, 4, 2, 2, 0, 1, 1, 1, 4, 1, 0, 4, 3, 2, 2, 2, 2, 0, 1, 3, 1, 3, 4, 2, 4, 2, 1, 3]
+
Finally, plot a scatter plot to visualize the 5 clusters in our sample size.
-```python PYTHON
+
+
+
+```python
+# Plot on a chart
df_clust.columns = df_clust.columns.astype(str)
generate_chart(df_clust.iloc[:sample],'0','1',lbl='off',color='cluster',title='Clustering with 5 Clusters')
```
+
+
+
+
+
+
+
+# Conclusion
Let's recap the NLP tasks implemented in this tutorial. You’ve created word embeddings, perform a semantic search, and text clustering. Cohere’s platform provides NLP tools that are easy and intuitive to integrate. You can create digital experiences that support powerful NLP capabilities like text clustering. It’s easy to Register a Cohere account and gain access to an API key. New cohere accounts have $75 free credits for the first 3 months. It also offers a Pay-as-you-go Pricing Model that bills you upon usage.
+
diff --git a/fern/pages/cookbooks/wikipedia-search-with-weaviate.mdx b/fern/pages/cookbooks/wikipedia-search-with-weaviate.mdx
index 2cc444e28..5ecd80d9b 100644
--- a/fern/pages/cookbooks/wikipedia-search-with-weaviate.mdx
+++ b/fern/pages/cookbooks/wikipedia-search-with-weaviate.mdx
@@ -3,23 +3,34 @@ title: Wikipedia Semantic Search with Cohere + Weaviate
slug: /page/wikipedia-search-with-weaviate
description: "This page contains a description of building a Wikipedia-focused search engine with Cohere's LLM platform and the Weaviate vector database."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, Weaviate, vector databases"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-This is starter code that you can use to search 10 million vectors from Wikipedia embedded with Cohere's multilingual model and hosted as a Weaviate public dataset. This dataset contains 1M vectors in each of the Wikipedia sites in these languages: English, German, French, Spanish, Italian, Japanese, Arabic, Chinese (Simplified), Korean, Hindi \[respective language codes: `en, de, fr, es, it, ja, ar, zh, ko, hi`\]
-```python PYTHON
+
+
+This is starter code that you can use to search 10 million vectors from wikipedia embedded with Cohere's multilingual model and hosted as a Weaviate public dataset. This dataset contains 1M vectors in each of the Wikipedia sites in these languages: English, German, French, Spanish, Italian, Japanese, Arabic, Chinese (Simplified), Korean, Hindi \[respective language codes: `en, de, fr, es, it, ja, ar, zh, ko, hi`\]
+
+
+```python
+# TODO: upgrade to "cohere>5"!pip install "cohere<5" weaviate-client
+```
+
+
+```python
import weaviate
+# Add your Cohere API key here
cohere_api_key = ''
-auth_config = weaviate.auth.AuthApiKey(api_key="76320a90-53d8-42bc-b41d-678647c6672e")
+# Connect to the Weaviate demo databse containing 10M wikipedia vectors
+# This uses a public READ-ONLY Weaviate API key
+auth_config = weaviate.auth.AuthApiKey(api_key="76320a90-53d8-42bc-b41d-678647c6672e")
client = weaviate.Client(
url="https://cohere-demo.weaviate.network/",
auth_client_secret=auth_config,
@@ -31,31 +42,35 @@ client = weaviate.Client(
client.is_ready() #check if True
```
-```txt title="Output"
-True
-```
+
+
+
+ True
+
+
Let's now define the search function that queries our vector database. Optionally, we want the ability to filter by language.
-```python PYTHON
+
+```python
def semantic_serch(query, results_lang=''):
- """
- Query the vectors database and return the top results.
+ """
+ Query the vectors database and return the top results.
Parameters
----------
query: str
The search query
-
+
results_lang: str (optional)
Retrieve results only in the specified language.
The demo dataset has those languages:
en, de, fr, es, it, ja, ar, zh, ko, hi
"""
-
+
nearText = {"concepts": [query]}
properties = ["text", "title", "url", "views", "lang", "_additional {distance}"]
@@ -74,7 +89,7 @@ def semantic_serch(query, results_lang=''):
.with_limit(5)
.do()
)
-
+
# Search all languages
else:
response = (
@@ -100,64 +115,67 @@ def print_result(result):
print()
```
-We can now query the database with any query we want. In the background, Weaviate uses your Cohere API key to embed the query, then retrun the most relevant passages to the query.
+We can now query the databse with any query we want. In the background, Weaviate uses your Cohere API key to embed the query, then retrun the most relevant passages to the query.
+
-```python PYTHON
+```python
query_result = semantic_serch("time travel plot twist")
+# Print out the result
print_result(query_result)
```
-```txt title="Output"
-[95mThe Adam Project (3000) -147.31755[0m
-[4mhttps://en.wikipedia.org/wiki?curid=65867428[0m
-Due to a safety feature preventing him from flying because of his injuries, Adam must bring along the younger Adam and use his DNA to enter his jet. They both are soon attacked by Maya Sorian, the leader of the dystopian world, and her assistant Christos, but are saved by Laura, who had faked her death and stayed off-grid in an unknown location. After surviving the attack and comparing notes, Laura and the Adams realize that after the invention of time travel by Louis Reed and his subsequent death, Sorian had monopolized the discovery. During her visit to 2018, Laura learned Sorian frequently came and advised her past self in order to secure her future wealth and power. To protect her secret, Sorian ordered Laura's death. Although Laura survived the assassination attempt, destruction of her time jet left her stranded in the past. The sudden arrival of Sorian's goons interrupts the reunion, and Laura fights off the attack long enough for the two Adams to escape to 2018.
-
-[95mKang the Conqueror (2000) -146.57275[0m
-[4mhttps://en.wikipedia.org/wiki?curid=393437[0m
-Nathaniel Richards, a 31st-century scholar and descendant of Reed Richards' time traveling father Nathaniel, becomes fascinated with history and discovers the time travel technology created by Victor von Doom, another possible ancestor of his. He then travels back in time to ancient Egypt aboard a Sphinx-shaped timeship and becomes the Pharaoh Rama-Tut, with plans to claim En Sabah Nur—the mutant destined to become Apocalypse—as his heir. Rama-Tut's rule is cut short when he is defeated by the time-displaced Fantastic Four. An embittered Nathaniel Richards travels forward to the 20th century where he meets Doctor Doom, whom he believes might be his ancestor. He later designs an armor based on Doom's and, calling himself the Scarlet Centurion, pits the Avengers team against alternate-reality counterparts. He plans to dispose of all of them, but the Avengers manage to force him from the timeline.
-
-[95mBack to the Future (3000) -146.4269[0m
-[4mhttps://en.wikipedia.org/wiki?curid=42993[0m
-That night, Marty meets his eccentric scientist friend, Emmett "Doc" Brown, in the Twin Pines mall parking lot. Doc unveils a time machine built from a modified DeLorean, powered by plutonium he swindled from Libyan terrorists. After Doc inputs a destination time of November5, 1955—the day he first conceived his time travel invention—the terrorists arrive unexpectedly and gun Doc down. Marty flees in the DeLorean, inadvertently activating time travel when he reaches .
-
-[95mTime (2000) -146.41129[0m
-[4mhttps://en.wikipedia.org/wiki?curid=30012[0m
-Time travel is the concept of moving backwards or forwards to different points in time, in a manner analogous to moving through space, and different from the normal "flow" of time to an earthbound observer. In this view, all points in time (including future times) "persist" in some way. Time travel has been a plot device in fiction since the 19th century. Travelling backwards or forwards in time has never been verified as a process, and doing so presents many theoretical problems and contradictive logic which to date have not been overcome. Any technological device, whether fictional or hypothetical, that is used to achieve time travel is known as a time machine.
+ [95mThe Adam Project (3000) -147.31755[0m
+ [4mhttps://en.wikipedia.org/wiki?curid=65867428[0m
+ Due to a safety feature preventing him from flying because of his injuries, Adam must bring along the younger Adam and use his DNA to enter his jet. They both are soon attacked by Maya Sorian, the leader of the dystopian world, and her assistant Christos, but are saved by Laura, who had faked her death and stayed off-grid in an unknown location. After surviving the attack and comparing notes, Laura and the Adams realize that after the invention of time travel by Louis Reed and his subsequent death, Sorian had monopolized the discovery. During her visit to 2018, Laura learned Sorian frequently came and advised her past self in order to secure her future wealth and power. To protect her secret, Sorian ordered Laura's death. Although Laura survived the assassination attempt, destruction of her time jet left her stranded in the past. The sudden arrival of Sorian's goons interrupts the reunion, and Laura fights off the attack long enough for the two Adams to escape to 2018.
+
+ [95mKang the Conqueror (2000) -146.57275[0m
+ [4mhttps://en.wikipedia.org/wiki?curid=393437[0m
+ Nathaniel Richards, a 31st-century scholar and descendant of Reed Richards' time traveling father Nathaniel, becomes fascinated with history and discovers the time travel technology created by Victor von Doom, another possible ancestor of his. He then travels back in time to ancient Egypt aboard a Sphinx-shaped timeship and becomes the Pharaoh Rama-Tut, with plans to claim En Sabah Nur—the mutant destined to become Apocalypse—as his heir. Rama-Tut's rule is cut short when he is defeated by the time-displaced Fantastic Four. An embittered Nathaniel Richards travels forward to the 20th century where he meets Doctor Doom, whom he believes might be his ancestor. He later designs an armor based on Doom's and, calling himself the Scarlet Centurion, pits the Avengers team against alternate-reality counterparts. He plans to dispose of all of them, but the Avengers manage to force him from the timeline.
+
+ [95mBack to the Future (3000) -146.4269[0m
+ [4mhttps://en.wikipedia.org/wiki?curid=42993[0m
+ That night, Marty meets his eccentric scientist friend, Emmett "Doc" Brown, in the Twin Pines mall parking lot. Doc unveils a time machine built from a modified DeLorean, powered by plutonium he swindled from Libyan terrorists. After Doc inputs a destination time of November5, 1955—the day he first conceived his time travel invention—the terrorists arrive unexpectedly and gun Doc down. Marty flees in the DeLorean, inadvertently activating time travel when he reaches .
+
+ [95mTime (2000) -146.41129[0m
+ [4mhttps://en.wikipedia.org/wiki?curid=30012[0m
+ Time travel is the concept of moving backwards or forwards to different points in time, in a manner analogous to moving through space, and different from the normal "flow" of time to an earthbound observer. In this view, all points in time (including future times) "persist" in some way. Time travel has been a plot device in fiction since the 19th century. Travelling backwards or forwards in time has never been verified as a process, and doing so presents many theoretical problems and contradictive logic which to date have not been overcome. Any technological device, whether fictional or hypothetical, that is used to achieve time travel is known as a time machine.
+
+ [95mIn Time (2000) -145.93015[0m
+ [4mhttps://en.wikipedia.org/wiki?curid=29446866[0m
+ Will and Sylvia rob Weis' time banks, giving the time capsules to the needy. They soon realize they can't significantly change anything, as prices are raised faster to compensate for the extra time. Fortis' gang ambushes them intending to collect the reward for their capture, but Will kills Fortis and his gang. Will and Sylvia then decide to rob Weis' vault of a one-million year capsule. Leon chases them back to Dayton but fails to stop them from distributing the stolen time; Leon times out, having neglected to collect his day's salary. Will and Sylvia nearly time out themselves but survive by taking Leon's salary.
+
-[95mIn Time (2000) -145.93015[0m
-[4mhttps://en.wikipedia.org/wiki?curid=29446866[0m
-Will and Sylvia rob Weis' time banks, giving the time capsules to the needy. They soon realize they can't significantly change anything, as prices are raised faster to compensate for the extra time. Fortis' gang ambushes them intending to collect the reward for their capture, but Will kills Fortis and his gang. Will and Sylvia then decide to rob Weis' vault of a one-million year capsule. Leon chases them back to Dayton but fails to stop them from distributing the stolen time; Leon times out, having neglected to collect his day's salary. Will and Sylvia nearly time out themselves but survive by taking Leon's salary.
-```
## Filtering by language
-
If we're interested in results in only one language, we can specify it.
-```python PYTHON
+
+```python
query_result = semantic_serch("time travel plot twist", results_lang='ja')
+# Print out the result
print_result(query_result)
```
-```txt title="Output"
-[95m時空の旅人 (500) -144.16002[0m
-[4mhttps://ja.wikipedia.org/wiki?curid=523464[0m
-バスは1868年の攘夷戦争で娘と夫を亡くした老婆の営む茶店に降り立つ。一時は老婆は一行を盗人と間違えて襲い掛かるも、ホクベンを亡き夫だと思い込んだことで一転して歓迎する。しかしそこへジロを追うタイムマシンがあらわれ、やむなく一行はバスに乗って走り去る。追い縋る老婆を見捨てられずバスを飛び降りたホクベンだが、直後にタイムマシンに攫われてしまった。
-
-[95m親殺しのパラドックス (700) -144.11864[0m
-[4mhttps://ja.wikipedia.org/wiki?curid=71910[0m
-パラドックスを防ぐアイデアとして、時間旅行者は元々の歴史とは異なる並行宇宙に行くのだと解釈するもので、上の科学的理論で述べたのと同じ考え方であり、SFにもよく見られる。歴史改変SFにあるタイムトラベル参照。
+ [95m時空の旅人 (500) -144.16002[0m
+ [4mhttps://ja.wikipedia.org/wiki?curid=523464[0m
+ バスは1868年の攘夷戦争で娘と夫を亡くした老婆の営む茶店に降り立つ。一時は老婆は一行を盗人と間違えて襲い掛かるも、ホクベンを亡き夫だと思い込んだことで一転して歓迎する。しかしそこへジロを追うタイムマシンがあらわれ、やむなく一行はバスに乗って走り去る。追い縋る老婆を見捨てられずバスを飛び降りたホクベンだが、直後にタイムマシンに攫われてしまった。
+
+ [95m親殺しのパラドックス (700) -144.11864[0m
+ [4mhttps://ja.wikipedia.org/wiki?curid=71910[0m
+ パラドックスを防ぐアイデアとして、時間旅行者は元々の歴史とは異なる並行宇宙に行くのだと解釈するもので、上の科学的理論で述べたのと同じ考え方であり、SFにもよく見られる。歴史改変SFにあるタイムトラベル参照。
+
+ [95mタイムトラベル (1000) -143.70331[0m
+ [4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
+ タイムパラドックスの矛盾を説明するため、タイムトラベル者による歴史の改変で時間軸が分岐し元の世界と並行した別の世界が生まれるとするパラレルワールドの概念がある。この概念を発展させ、タイムトラベル者の介在がなくとも歴史上の重要なポイントで世界が枝分かれしていると解釈する立場もある。この概念を大幅に作品に取り入れた最初期の小説に、可能性として存在する二つの歴史「ジョンバール」と「ギロンチ」の抗争を描いた、ジャック・ウィリアムスンの『航時軍団』(The Legion of Time、1938年)がある。
+
+ [95mタイムトラベル (1000) -143.69884[0m
+ [4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
+ タイムトラベラーが主人公であるマーク・トウェインの「アーサー王宮廷のコネチカット・ヤンキー」や、天使が未来の書物を携えて現れるサミュエル・マッデンの「20世紀回想」など、SFというカテゴリが明確なものとして育つ以前から、タイムトラベルをテーマにした物語は創られている。
+
+ [95mタイムトラベル (1000) -143.61562[0m
+ [4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
+ タイムパラドックス(Time Paradox / 時間の逆説)は、タイムトラベルに伴う矛盾や変化のことであり、物語のテーマとしてしばしば扱われる。具体的には、タイムトラベルした過去で現代(相対的未来)に存在する事象を改変した場合、その事象における過去と現代の存在や状況、因果関係の不一致という逆説が生じることに着目したものである。
+
-[95mタイムトラベル (1000) -143.70331[0m
-[4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
-タイムパラドックスの矛盾を説明するため、タイムトラベル者による歴史の改変で時間軸が分岐し元の世界と並行した別の世界が生まれるとするパラレルワールドの概念がある。この概念を発展させ、タイムトラベル者の介在がなくとも歴史上の重要なポイントで世界が枝分かれしていると解釈する立場もある。この概念を大幅に作品に取り入れた最初期の小説に、可能性として存在する二つの歴史「ジョンバール」と「ギロンチ」の抗争を描いた、ジャック・ウィリアムスンの『航時軍団』(The Legion of Time、1938年)がある。
-
-[95mタイムトラベル (1000) -143.69884[0m
-[4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
-タイムトラベラーが主人公であるマーク・トウェインの「アーサー王宮廷のコネチカット・ヤンキー」や、天使が未来の書物を携えて現れるサミュエル・マッデンの「20世紀回想」など、SFというカテゴリが明確なものとして育つ以前から、タイムトラベルをテーマにした物語は創られている。
-
-[95mタイムトラベル (1000) -143.61562[0m
-[4mhttps://ja.wikipedia.org/wiki?curid=1971274[0m
-タイムパラドックス(Time Paradox / 時間の逆説)は、タイムトラベルに伴う矛盾や変化のことであり、物語のテーマとしてしばしば扱われる。具体的には、タイムトラベルした過去で現代(相対的未来)に存在する事象を改変した場合、その事象における過去と現代の存在や状況、因果関係の不一致という逆説が生じることに着目したものである。
-```
diff --git a/fern/pages/cookbooks/wikipedia-semantic-search.mdx b/fern/pages/cookbooks/wikipedia-semantic-search.mdx
index 23877aea9..a3dc422ad 100644
--- a/fern/pages/cookbooks/wikipedia-semantic-search.mdx
+++ b/fern/pages/cookbooks/wikipedia-semantic-search.mdx
@@ -3,25 +3,35 @@ title: Wikipedia Semantic Search with Cohere Embedding Archives
slug: /page/wikipedia-semantic-search
description: "This page contains a description of building a Wikipedia-focused semantic search engine with Cohere's LLM platform and the Weaviate vector database."
-image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
+image: "../../assets/images/f1cc130-cohere_meta_image.jpg"
keywords: "Cohere, Weaviate, vector databases, semantic search"
---
import { AuthorsContainer } from "../../components/authors-container";
import { CookbookHeader } from "../../components/cookbook-header";
-
-This notebook contains the starter code to do simple [semantic search](https://cohere.com/llmu/what-is-semantic-search/) on the [Wikipedia embeddings archives](https://cohere.com/blog/embedding-archives-wikipedia/) published by Cohere. These archives embed Wikipedia sites in multiple languages. In this example, we'll use [Wikipedia Simple English](https://huggingface.co/datasets/Cohere/wikipedia-22-12-simple-embeddings).
+
+
+
+This notebook contains the starter code to do simple [semantic search](https://txt.cohere.ai/what-is-semantic-search/) on the [Wikipedia embeddings archives](https://txt.cohere.ai/embedding-archives-wikipedia/) published by Cohere. These archives embed Wikipedia sites in multiple languages. In this example, we'll use [Wikipedia Simple English](https://huggingface.co/datasets/Cohere/wikipedia-22-12-simple-embeddings).
+
+
+```python
+# Let's install "cohere<5" and HF datasets
+# TODO: upgrade to "cohere>5"!pip install "cohere<5" datasets
+```
Let's now download 1,000 records from the English Wikipedia embeddings archive so we can search it afterwards.
-```python PYTHON
+
+```python
from datasets import load_dataset
import torch
import cohere
-s
-co = cohere.Client("")
+
+# Add your cohere API key from www.cohere.com
+co = cohere.Client("")
#Load at max 1000 documents + embeddings
max_docs = 1000
@@ -39,37 +49,45 @@ for doc in docs_stream:
doc_embeddings = torch.tensor(doc_embeddings)
```
-```txt title="Output"
-Downloading: 0%| | 0.00/1.29k [00:00, ?B/s]
+ Downloading: 0%| | 0.00/1.29k [00:00, ?B/s]
+
+
+ Using custom data configuration Cohere--wikipedia-22-12-simple-embeddings-94deea3d55a22093
-Using custom data configuration Cohere--wikipedia-22-12-simple-embeddings-94deea3d55a22093
-```
-Now, `doc_embeddings` holds the embeddings of the first 1,000 documents in the dataset. Each document is represented as an [embeddings vector](https://cohere.com/llmu/sentence-word-embeddings/) of 768 values.
+Now, `doc_embeddings` holds the embeddings of the first 1,000 documents in the dataset. Each document is represented as an [embeddings vector](https://txt.cohere.ai/sentence-word-embeddings/) of 768 values.
-```python PYTHON
+
+```python
doc_embeddings.shape
```
-```txt title="Output"
-torch.Size([1000, 768])
-```
+
+
+
+ torch.Size([1000, 768])
+
+
We can now search these vectors for any query we want. For this toy example, we'll ask a question about Wikipedia since we know the Wikipedia page is included in the first 1000 documents we used here.
To search, we embed the query, then get the nearest neighbors to its embedding (using dot product).
-```python PYTHON
+```python
+
+# Get the query, then embed it
query = 'Who founded Wikipedia'
response = co.embed(texts=[query], model='multilingual-22-12')
-query_embedding = response.embeddings
+query_embedding = response.embeddings
query_embedding = torch.tensor(query_embedding)
+# Compute dot score between query embedding and document embeddings
dot_scores = torch.mm(query_embedding, doc_embeddings.transpose(0, 1))
top_k = torch.topk(dot_scores, k=3)
+# Print results
print("Query:", query)
for doc_id in top_k.indices[0].tolist():
print(docs[doc_id]['title'])
@@ -77,16 +95,16 @@ for doc_id in top_k.indices[0].tolist():
```
-```txt title="Output"
-Query: Who founded Wikipedia
-Wikipedia
-Larry Sanger and Jimmy Wales are the ones who started Wikipedia. Wales is credited with defining the goals of the project. Sanger created the strategy of using a wiki to reach Wales' goal. On January 10, 2001, Larry Sanger proposed on the Nupedia mailing list to create a wiki as a "feeder" project for Nupedia. Wikipedia was launched on January 15, 2001. It was launched as an English-language edition at www.wikipedia.com, and announced by Sanger on the Nupedia mailing list. Wikipedia's policy of "neutral point-of-view" was enforced in its initial months, and was similar to Nupedia's earlier "nonbiased" policy. Otherwise, there weren't very many rules initially, and Wikipedia operated independently of Nupedia.
+ Query: Who founded Wikipedia
+ Wikipedia
+ Larry Sanger and Jimmy Wales are the ones who started Wikipedia. Wales is credited with defining the goals of the project. Sanger created the strategy of using a wiki to reach Wales' goal. On January 10, 2001, Larry Sanger proposed on the Nupedia mailing list to create a wiki as a "feeder" project for Nupedia. Wikipedia was launched on January 15, 2001. It was launched as an English-language edition at www.wikipedia.com, and announced by Sanger on the Nupedia mailing list. Wikipedia's policy of "neutral point-of-view" was enforced in its initial months, and was similar to Nupedia's earlier "nonbiased" policy. Otherwise, there weren't very many rules initially, and Wikipedia operated independently of Nupedia.
+
+ Wikipedia
+ Wikipedia began as a related project for Nupedia. Nupedia was a free English-language online encyclopedia project. Nupedia's articles were written and owned by Bomis, Inc which was a web portal company. The important people of the company were Jimmy Wales, the person in charge of Bomis, and Larry Sanger, the editor-in-chief of Nupedia. Nupedia was first licensed under the Nupedia Open Content License which was changed to the GNU Free Documentation License before Wikipedia was founded and made their first article when Richard Stallman requested them.
+
+ Wikipedia
+ Wikipedia was started on January 10, 2001, by Jimmy Wales and Larry Sanger as part of an earlier online encyclopedia named Nupedia. On January 15, 2001, Wikipedia became a separate website of its own. It is a wiki that uses the software MediaWiki (like all other Wikimedia Foundation projects).
+
-Wikipedia
-Wikipedia began as a related project for Nupedia. Nupedia was a free English-language online encyclopedia project. Nupedia's articles were written and owned by Bomis, Inc which was a web portal company. The important people of the company were Jimmy Wales, the person in charge of Bomis, and Larry Sanger, the editor-in-chief of Nupedia. Nupedia was first licensed under the Nupedia Open Content License which was changed to the GNU Free Documentation License before Wikipedia was founded and made their first article when Richard Stallman requested them.
-
-Wikipedia
-Wikipedia was started on January 10, 2001, by Jimmy Wales and Larry Sanger as part of an earlier online encyclopedia named Nupedia. On January 15, 2001, Wikipedia became a separate website of its own. It is a wiki that uses the software MediaWiki (like all other Wikimedia Foundation projects).
-```
This shows the top three passages that are relevant to the query. We can retrieve more results by changing the `k` value. The question in this simple demo is about Wikipedia because we know that the Wikipedia page is part of the documents in this subset of the archive.
diff --git a/notebooks/agents/Vanilla_Multi_Step_Tool_Use.ipynb b/notebooks/agents/Vanilla_Multi_Step_Tool_Use.ipynb
index 550e7d87f..6bb5d60df 100644
--- a/notebooks/agents/Vanilla_Multi_Step_Tool_Use.ipynb
+++ b/notebooks/agents/Vanilla_Multi_Step_Tool_Use.ipynb
@@ -1,21 +1,10 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "provenance": []
- },
- "kernelspec": {
- "name": "python3",
- "display_name": "Python 3"
- },
- "language_info": {
- "name": "python"
- }
- },
"cells": [
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "aH1iAdZiURXh"
+ },
"source": [
"# Multi-Step Tool Use\n",
"\n",
@@ -24,19 +13,16 @@
"Multi-step tool use is an extension of this basic idea, and allows the model to call more than one tool in a sequence of steps, using the results from one tool call in a subsequent step. This process allows the language model to reason, perform dynamic actions, and quickly adapt on the basis of information coming from external sources.\n",
"\n",
"The recommended way to achieve [multi-step tool use with Cohere](https://docs.cohere.com/docs/multi-step-tool-use) is by leveraging the [Langchain framework](https://python.langchain.com/docs/integrations/providers/cohere#react-agent) in Python."
- ],
- "metadata": {
- "id": "aH1iAdZiURXh"
- }
+ ]
},
{
"cell_type": "markdown",
- "source": [
- "## Install Dependencies"
- ],
"metadata": {
"id": "PVT6Sl3msjNe"
- }
+ },
+ "source": [
+ "## Install Dependencies"
+ ]
},
{
"cell_type": "code",
@@ -50,8 +36,8 @@
},
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m812.8/812.8 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m194.1/194.1 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
@@ -76,19 +62,22 @@
},
{
"cell_type": "code",
- "source": [
- "# LLM\n",
- "import os\n",
- "os.environ['COHERE_API_KEY'] = "
- ],
+ "execution_count": 2,
"metadata": {
"id": "K0GELKJVnadW"
},
- "execution_count": 2,
- "outputs": []
+ "outputs": [],
+ "source": [
+ "# LLM\n",
+ "import os\n",
+ "os.environ['COHERE_API_KEY'] = \"\""
+ ]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "6l1pDbAmsptW"
+ },
"source": [
"## Define tools\n",
"\n",
@@ -100,23 +89,25 @@
"- and/or directly answering [ this tool comes out of the box! ]\n",
"\n",
"Plus the model can self-reflect."
- ],
- "metadata": {
- "id": "6l1pDbAmsptW"
- }
+ ]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "_9riBTvIVnaN"
+ },
"source": [
"#### Web search\n",
"You can easily equip your agent with web search!"
- ],
- "metadata": {
- "id": "_9riBTvIVnaN"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "id": "6wMNTOGNVvwA"
+ },
+ "outputs": [],
"source": [
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
"\n",
@@ -131,50 +122,50 @@
"class TavilySearchInput(BaseModel):\n",
" query: str = Field(description=\"Query to search the internet with\")\n",
"internet_search.args_schema = TavilySearchInput"
- ],
- "metadata": {
- "id": "6wMNTOGNVvwA"
- },
- "execution_count": 3,
- "outputs": []
+ ]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "pax1SemzX6Kg"
+ },
"source": [
"#### Vector store\n",
"You can easily equip your agent with a vector store!"
- ],
- "metadata": {
- "id": "pax1SemzX6Kg"
- }
+ ]
},
{
"cell_type": "code",
- "source": [
- "!pip --quiet install faiss-cpu tiktoken"
- ],
+ "execution_count": 4,
"metadata": {
- "id": "cc4d4pRFndYu",
"colab": {
"base_uri": "https://localhost:8080/"
},
+ "id": "cc4d4pRFndYu",
"outputId": "6478fd6b-5618-4d0b-8928-44f78e3ca7e6"
},
- "execution_count": 4,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m27.0/27.0 MB\u001b[0m \u001b[31m41.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m58.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25h"
]
}
+ ],
+ "source": [
+ "!pip --quiet install faiss-cpu tiktoken"
]
},
{
"cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "id": "eqcorKP4YEH6"
+ },
+ "outputs": [],
"source": [
"from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
"from langchain_community.document_loaders import WebBaseLoader\n",
@@ -206,15 +197,15 @@
")\n",
"\n",
"vectorstore_retriever = vectorstore.as_retriever()\n"
- ],
- "metadata": {
- "id": "eqcorKP4YEH6"
- },
- "execution_count": 5,
- "outputs": []
+ ]
},
{
"cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "id": "eQFNJ-38abRd"
+ },
+ "outputs": [],
"source": [
"from langchain.tools.retriever import create_retriever_tool\n",
"\n",
@@ -223,25 +214,25 @@
" name=\"vectorstore_search\",\n",
" description=\"Retrieve relevant info from a vectorstore that contains information from Paul Graham about how to write good essays.\"\n",
")"
- ],
- "metadata": {
- "id": "eQFNJ-38abRd"
- },
- "execution_count": 6,
- "outputs": []
+ ]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "aB90i9W5YqWi"
+ },
"source": [
"#### Python interpreter tool\n",
"You can easily equip your agent with a python interpreter!"
- ],
- "metadata": {
- "id": "aB90i9W5YqWi"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "id": "AN-4FqXKYEFw"
+ },
+ "outputs": [],
"source": [
"from langchain.agents import Tool\n",
"from langchain_experimental.utilities import PythonREPL\n",
@@ -258,34 +249,34 @@
"class ToolInput(BaseModel):\n",
" code: str = Field(description=\"Python code to execute.\")\n",
"python_tool.args_schema = ToolInput"
- ],
- "metadata": {
- "id": "AN-4FqXKYEFw"
- },
- "execution_count": 7,
- "outputs": []
+ ]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": 7,
"metadata": {
"id": "8vj868w_YED_"
},
- "execution_count": 7,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "2SDCaoypexGL"
+ },
"source": [
"#### Transform any Python function in a Tool\n",
"You can easily equip your agent with any Python function!"
- ],
- "metadata": {
- "id": "2SDCaoypexGL"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "id": "DYUJT2xKewny"
+ },
+ "outputs": [],
"source": [
"from langchain_core.tools import tool\n",
"import random\n",
@@ -307,27 +298,27 @@
" a: int = Field(description=\"First input\")\n",
" b: int = Field(description=\"Second input\")\n",
"random_operation_tool.args_schema = random_operation_inputs"
- ],
- "metadata": {
- "id": "DYUJT2xKewny"
- },
- "execution_count": 8,
- "outputs": []
+ ]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "hcspRBsRY2ED"
+ },
"source": [
"## Create ReAct Agent\n",
"\n",
"The model can smartly pick the right tool(s) for the user query, call them in any sequence, analyze the results and self-reflect. \n",
"Once the model considers it has enough information to answer the user question, it generates the final answer."
- ],
- "metadata": {
- "id": "hcspRBsRY2ED"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "id": "CY83aAprYECO"
+ },
+ "outputs": [],
"source": [
"from langchain.agents import AgentExecutor\n",
"from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent\n",
@@ -355,44 +346,30 @@
")\n",
"\n",
"agent_executor = AgentExecutor(agent=agent, tools=[internet_search, vectorstore_search, python_tool, random_operation_tool], verbose=True)"
- ],
- "metadata": {
- "id": "CY83aAprYECO"
- },
- "execution_count": 13,
- "outputs": []
+ ]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": 13,
"metadata": {
"id": "RK0NaqngYD_J"
},
- "execution_count": 13,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "mzTQcVXSaBe7"
+ },
"source": [
"## Ask a standalone question to the ReAct agent\n",
"A question that requires using a predefined tool from Langchain"
- ],
- "metadata": {
- "id": "mzTQcVXSaBe7"
- }
+ ]
},
{
"cell_type": "code",
- "source": [
- "response = agent_executor.invoke({\n",
- " \"input\": \"I want to write an essay about the Roman Empire. Any tips for writing an essay? Any fun facts?\",\n",
- " \"preamble\": preamble,\n",
- "})\n",
- "\n",
- "response['output']\n",
- "\n",
- "# note that the model smartly looks in the vector db, and then online"
- ],
+ "execution_count": 14,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -401,11 +378,10 @@
"id": "rR2hWVp-aEsU",
"outputId": "fcf9b8b3-7027-4679-c06d-ef166f016892"
},
- "execution_count": 14,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\n",
"\n",
@@ -580,50 +556,51 @@
]
},
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- "\"Here are some tips for writing an essay:\\n- Start with a question that spurs some response.\\n- Don't choose a topic at random, make sure you have a way in, a new insight or approach.\\n- You don't need a complete thesis, just a gap to explore.\\n- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.\\n- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.\\n- You can get breadth by reading and talking about a wide range of topics.\\n- You can get depth by doing and having to solve problems.\\n- You can also get ideas by talking to people who make you have new ideas.\\n\\nHere are some fun facts about the Roman Empire:\\n- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.\\n- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.\\n- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.\""
- ],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
- }
+ },
+ "text/plain": [
+ "\"Here are some tips for writing an essay:\\n- Start with a question that spurs some response.\\n- Don't choose a topic at random, make sure you have a way in, a new insight or approach.\\n- You don't need a complete thesis, just a gap to explore.\\n- You can get ideas by talking to people, reading, doing and building things, and going places and seeing things.\\n- You can improve the quality of your ideas by increasing the breadth and depth of what goes in.\\n- You can get breadth by reading and talking about a wide range of topics.\\n- You can get depth by doing and having to solve problems.\\n- You can also get ideas by talking to people who make you have new ideas.\\n\\nHere are some fun facts about the Roman Empire:\\n- At its peak, the empire stretched from North Africa to Britain, reigning over 60 million people.\\n- The story of Rome's warrior founder and the twins and their wolf step-mother was depicted on Rome's first coins.\\n- The Crossing of the Rhine in 405/6 AD brought around 100,000 barbarians into the Empire.\""
+ ]
},
+ "execution_count": 14,
"metadata": {},
- "execution_count": 14
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "response = agent_executor.invoke({\n",
+ " \"input\": \"I want to write an essay about the Roman Empire. Any tips for writing an essay? Any fun facts?\",\n",
+ " \"preamble\": preamble,\n",
+ "})\n",
+ "\n",
+ "response['output']\n",
+ "\n",
+ "# note that the model smartly looks in the vector db, and then online"
]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": 14,
"metadata": {
"id": "DIP1YkXCg7rQ"
},
- "execution_count": 14,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
- "source": [
- "A question that requires the large language model to use a custom tool."
- ],
"metadata": {
"id": "FhwS3VHvg3_l"
- }
+ },
+ "source": [
+ "A question that requires the large language model to use a custom tool."
+ ]
},
{
"cell_type": "code",
- "source": [
- "response = agent_executor.invoke({\n",
- " \"input\": \"Calculate the result of the random operation of 10 and 20. Then find a few fun facts about that number, as well as its prime factors.\",\n",
- " \"preamble\": preamble,\n",
- "})\n",
- "\n",
- "response['output']\n",
- "\n",
- "# note that the model uses a sequence of tools"
- ],
+ "execution_count": 22,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -632,11 +609,10 @@
"id": "79Dw6Zhrg3xI",
"outputId": "a41c6de9-cb64-4cff-a58b-e9481d438f6c"
},
- "execution_count": 22,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\n",
"\n",
@@ -672,50 +648,51 @@
]
},
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- "\"The result of the random operation is **200**. Here are some fun facts about the number 200:\\n- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.\\n- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.\\n- The number 200 is an even composite number composed of two distinct primes.\\n\\nThe prime factors of 200 are 2 and 5.\""
- ],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
- }
+ },
+ "text/plain": [
+ "\"The result of the random operation is **200**. Here are some fun facts about the number 200:\\n- It is the smallest base 10 unprimeable number, meaning it cannot be turned into a prime number by changing just one of its digits to any other digit.\\n- According to Bullinger's study of biblical literature, the number 200 signifies 'insufficiency'.\\n- The number 200 is an even composite number composed of two distinct primes.\\n\\nThe prime factors of 200 are 2 and 5.\""
+ ]
},
+ "execution_count": 22,
"metadata": {},
- "execution_count": 22
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "response = agent_executor.invoke({\n",
+ " \"input\": \"Calculate the result of the random operation of 10 and 20. Then find a few fun facts about that number, as well as its prime factors.\",\n",
+ " \"preamble\": preamble,\n",
+ "})\n",
+ "\n",
+ "response['output']\n",
+ "\n",
+ "# note that the model uses a sequence of tools"
]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": 15,
"metadata": {
"id": "V8LcAh8vaEqR"
},
- "execution_count": 15,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
- "source": [
- "A question that requires the large language model to directly answer."
- ],
"metadata": {
"id": "n9nV_jiaAaD1"
- }
+ },
+ "source": [
+ "A question that requires the large language model to directly answer."
+ ]
},
{
"cell_type": "code",
- "source": [
- "response = agent_executor.invoke({\n",
- " \"input\": \"Hey how are you?\",\n",
- " \"preamble\": preamble,\n",
- "})\n",
- "\n",
- "response['output']\n",
- "\n",
- "# note that the modle can directly answer!"
- ],
+ "execution_count": 23,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -724,11 +701,10 @@
"id": "tRf6V3gJAZkO",
"outputId": "aec1acdb-876c-48e9-a1f5-e3ba8a0f19ed"
},
- "execution_count": 23,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\n",
"\n",
@@ -745,49 +721,52 @@
]
},
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- "\"I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?\""
- ],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
- }
+ },
+ "text/plain": [
+ "\"I'm an AI chatbot, so I don't have feelings as such, but I'm here to help you with your queries. How can I help?\""
+ ]
},
+ "execution_count": 23,
"metadata": {},
- "execution_count": 23
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "response = agent_executor.invoke({\n",
+ " \"input\": \"Hey how are you?\",\n",
+ " \"preamble\": preamble,\n",
+ "})\n",
+ "\n",
+ "response['output']\n",
+ "\n",
+ "# note that the modle can directly answer!"
]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": null,
"metadata": {
"id": "hnLkln_ckYXJ"
},
- "execution_count": null,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "3h-icRL2_5iu"
+ },
"source": [
"## Ask a more complex question to the ReAct agent\n",
"A question that requires using multipe tools, in sequence"
- ],
- "metadata": {
- "id": "3h-icRL2_5iu"
- }
+ ]
},
{
"cell_type": "code",
- "source": [
- "response = agent_executor.invoke({\n",
- " \"input\": \"In what year was the company that was founded as Sound of Music went public? What was its stock price in 2000 and 2010.\",\n",
- " \"preamble\": preamble,\n",
- "})\n",
- "\n",
- "response['output']"
- ],
+ "execution_count": 27,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -796,11 +775,10 @@
"id": "Q4IyoXXRaEoL",
"outputId": "0e935f68-8b7c-4d9a-b8f1-1be57b7c9a1f"
},
- "execution_count": 27,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\n",
"\n",
@@ -822,41 +800,54 @@
]
},
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- "'Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.'"
- ],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
- }
+ },
+ "text/plain": [
+ "'Best Buy, which was founded as Sound of Music, went public in 1985. Its stock price in 2000 was between $5.93 and $16.24 and in 2010, it was between $20.27 and $31.24.'"
+ ]
},
+ "execution_count": 27,
"metadata": {},
- "execution_count": 27
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "response = agent_executor.invoke({\n",
+ " \"input\": \"In what year was the company that was founded as Sound of Music went public? What was its stock price in 2000 and 2010.\",\n",
+ " \"preamble\": preamble,\n",
+ "})\n",
+ "\n",
+ "response['output']"
]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": null,
"metadata": {
"id": "L1BsKueTaEmg"
},
- "execution_count": null,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "53FDSFzQBFyf"
+ },
"source": [
"## Have a multi-turn conversation with the ReAct agent\n",
"The chat history enables you to have multi-turn conversations with the ReAct agent."
- ],
- "metadata": {
- "id": "53FDSFzQBFyf"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "id": "1iYyAExsaEk9"
+ },
+ "outputs": [],
"source": [
"# Step 1: Construct the chat history as a list of LangChain Messages, ending with the last user message\n",
"from langchain_core.messages import HumanMessage, AIMessage\n",
@@ -868,15 +859,15 @@
"]\n",
"\n",
"prompt = ChatPromptTemplate.from_messages(chat_history)"
- ],
- "metadata": {
- "id": "1iYyAExsaEk9"
- },
- "execution_count": 28,
- "outputs": []
+ ]
},
{
"cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "id": "fyv_1LedaEi7"
+ },
+ "outputs": [],
"source": [
"# Step 2: When you make the agent, specify the chat_history as the prompt, e.g.\n",
"# Create the ReAct agent\n",
@@ -887,36 +878,23 @@
")\n",
"\n",
"agent_executor = AgentExecutor(agent=agent, tools=[internet_search, vectorstore_search, python_tool], verbose=True)"
- ],
- "metadata": {
- "id": "fyv_1LedaEi7"
- },
- "execution_count": 29,
- "outputs": []
+ ]
},
{
"cell_type": "code",
- "source": [
- "# Step 3: When you invoke the agent_executor there's no need to pass anything else into invoke\n",
- "response = agent_executor.invoke({\n",
- " \"preamble\": preamble,\n",
- "})\n",
- "\n",
- "response['output']"
- ],
+ "execution_count": 30,
"metadata": {
- "id": "-ZCFj-m5nqFw",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 538
},
+ "id": "-ZCFj-m5nqFw",
"outputId": "3d71931e-1644-49b9-903c-4ff117787868"
},
- "execution_count": 30,
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"\n",
"\n",
@@ -943,37 +921,59 @@
]
},
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- "\"Oracle's CRM offering includes the following:\\n- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing\\n- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI\\n- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries\\n- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction\\n- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM\""
- ],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
- }
+ },
+ "text/plain": [
+ "\"Oracle's CRM offering includes the following:\\n- Marketing Cloud, which provides a comprehensive set of tools that cover a range of digital marketing needs, including cross-channel marketing, marketing automation, data management, content marketing and social media marketing\\n- CRM On Demand, which is a full-featured marketing automation product with features from lead management and nurturing, to measuring marketing ROI\\n- Siebel CRM, which delivers a combination of transactional, analytical, and engagement features to manage all customer-facing operations, with solutions tailored to more than 20 industries\\n- Siebel CRM Life Sciences, which provides personalised content delivery tools to help sales and marketing teams deliver the right messages during each customer interaction\\n- Oracle Client Experience (CX), a connected suite of tools that transcends standard CRM\""
+ ]
},
+ "execution_count": 30,
"metadata": {},
- "execution_count": 30
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "# Step 3: When you invoke the agent_executor there's no need to pass anything else into invoke\n",
+ "response = agent_executor.invoke({\n",
+ " \"preamble\": preamble,\n",
+ "})\n",
+ "\n",
+ "response['output']"
]
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": 30,
"metadata": {
"id": "8Zh01M4hWw3L"
},
- "execution_count": 30,
- "outputs": []
+ "outputs": [],
+ "source": []
},
{
"cell_type": "code",
- "source": [],
+ "execution_count": null,
"metadata": {
"id": "0qEPY6xj_qwr"
},
- "execution_count": null,
- "outputs": []
+ "outputs": [],
+ "source": []
}
- ]
-}
\ No newline at end of file
+ ],
+ "metadata": {
+ "colab": {
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/poetry.lock b/poetry.lock
index 48492ac19..8d9cf7a23 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -31,6 +31,46 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)",
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"]
trio = ["trio (>=0.26.1)"]
+[[package]]
+name = "attrs"
+version = "24.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
+ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
+tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+
+[[package]]
+name = "beautifulsoup4"
+version = "4.12.3"
+description = "Screen-scraping library"
+optional = false
+python-versions = ">=3.6.0"
+files = [
+ {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"},
+ {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"},
+]
+
+[package.dependencies]
+soupsieve = ">1.2"
+
+[package.extras]
+cchardet = ["cchardet"]
+chardet = ["chardet"]
+charset-normalizer = ["charset-normalizer"]
+html5lib = ["html5lib"]
+lxml = ["lxml"]
+
[[package]]
name = "black"
version = "24.10.0"
@@ -75,6 +115,23 @@ d = ["aiohttp (>=3.10)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
+[[package]]
+name = "bleach"
+version = "6.2.0"
+description = "An easy safelist-based HTML-sanitizing tool."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"},
+ {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"},
+]
+
+[package.dependencies]
+webencodings = "*"
+
+[package.extras]
+css = ["tinycss2 (>=1.1.0,<1.5)"]
+
[[package]]
name = "certifi"
version = "2024.8.30"
@@ -86,6 +143,85 @@ files = [
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
]
+[[package]]
+name = "cffi"
+version = "1.17.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
+ {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
+ {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
+ {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
+ {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
+ {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
+ {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
+ {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
+ {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
+ {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
+ {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
+ {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
+ {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
+ {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
+ {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
+ {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
[[package]]
name = "charset-normalizer"
version = "3.4.0"
@@ -251,6 +387,17 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+[[package]]
+name = "defusedxml"
+version = "0.7.1"
+description = "XML bomb protection for Python stdlib modules"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
+ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
+]
+
[[package]]
name = "fastavro"
version = "1.9.7"
@@ -297,6 +444,20 @@ lz4 = ["lz4"]
snappy = ["cramjam"]
zstandard = ["zstandard"]
+[[package]]
+name = "fastjsonschema"
+version = "2.21.1"
+description = "Fastest Python implementation of JSON schema"
+optional = false
+python-versions = "*"
+files = [
+ {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"},
+ {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"},
+]
+
+[package.extras]
+devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"]
+
[[package]]
name = "filelock"
version = "3.16.1"
@@ -468,6 +629,250 @@ files = [
[package.extras]
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
+[[package]]
+name = "jinja2"
+version = "3.1.4"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
+ {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "jsonschema"
+version = "4.23.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
+ {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2024.10.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"},
+ {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"},
+]
+
+[package.dependencies]
+referencing = ">=0.31.0"
+
+[[package]]
+name = "jupyter-client"
+version = "8.6.3"
+description = "Jupyter protocol implementation and client libraries"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"},
+ {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"},
+]
+
+[package.dependencies]
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
+python-dateutil = ">=2.8.2"
+pyzmq = ">=23.0"
+tornado = ">=6.2"
+traitlets = ">=5.3"
+
+[package.extras]
+docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"]
+test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"]
+
+[[package]]
+name = "jupyter-core"
+version = "5.7.2"
+description = "Jupyter core package. A base package on which Jupyter projects rely."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"},
+ {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"},
+]
+
+[package.dependencies]
+platformdirs = ">=2.5"
+pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
+traitlets = ">=5.3"
+
+[package.extras]
+docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"]
+test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"]
+
+[[package]]
+name = "jupyterlab-pygments"
+version = "0.3.0"
+description = "Pygments theme using JupyterLab CSS variables"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"},
+ {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"},
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.2"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
+ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
+]
+
+[[package]]
+name = "mistune"
+version = "3.0.2"
+description = "A sane and fast Markdown parser with useful plugins and renderers"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"},
+ {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"},
+]
+
+[[package]]
+name = "mypy"
+version = "1.14.1"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"},
+ {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"},
+ {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"},
+ {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"},
+ {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"},
+ {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"},
+ {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"},
+ {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"},
+ {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"},
+ {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"},
+ {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"},
+ {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"},
+ {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"},
+ {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"},
+ {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"},
+ {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"},
+ {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"},
+ {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"},
+ {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"},
+ {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"},
+ {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"},
+ {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"},
+ {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"},
+ {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"},
+ {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"},
+ {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"},
+ {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"},
+ {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"},
+ {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"},
+ {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"},
+ {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"},
+ {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"},
+ {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"},
+ {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"},
+ {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"},
+ {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"},
+ {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"},
+ {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"},
+]
+
+[package.dependencies]
+mypy_extensions = ">=1.0.0"
+typing_extensions = ">=4.6.0"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+faster-cache = ["orjson"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
+
[[package]]
name = "mypy-extensions"
version = "1.0.0"
@@ -479,6 +884,86 @@ files = [
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
+[[package]]
+name = "nbclient"
+version = "0.10.1"
+description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d"},
+ {file = "nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68"},
+]
+
+[package.dependencies]
+jupyter-client = ">=6.1.12"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
+nbformat = ">=5.1"
+traitlets = ">=5.4"
+
+[package.extras]
+dev = ["pre-commit"]
+docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"]
+test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"]
+
+[[package]]
+name = "nbconvert"
+version = "7.16.4"
+description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3"},
+ {file = "nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4"},
+]
+
+[package.dependencies]
+beautifulsoup4 = "*"
+bleach = "!=5.0.0"
+defusedxml = "*"
+jinja2 = ">=3.0"
+jupyter-core = ">=4.7"
+jupyterlab-pygments = "*"
+markupsafe = ">=2.0"
+mistune = ">=2.0.3,<4"
+nbclient = ">=0.5.0"
+nbformat = ">=5.7"
+packaging = "*"
+pandocfilters = ">=1.4.1"
+pygments = ">=2.4.1"
+tinycss2 = "*"
+traitlets = ">=5.1"
+
+[package.extras]
+all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"]
+docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"]
+qtpdf = ["pyqtwebengine (>=5.15)"]
+qtpng = ["pyqtwebengine (>=5.15)"]
+serve = ["tornado (>=6.1)"]
+test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"]
+webpdf = ["playwright"]
+
+[[package]]
+name = "nbformat"
+version = "5.10.4"
+description = "The Jupyter Notebook format"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"},
+ {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"},
+]
+
+[package.dependencies]
+fastjsonschema = ">=2.15"
+jsonschema = ">=2.6"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
+traitlets = ">=5.1"
+
+[package.extras]
+docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"]
+test = ["pep440", "pre-commit", "pytest", "testpath"]
+
[[package]]
name = "packaging"
version = "24.1"
@@ -490,6 +975,17 @@ files = [
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
+[[package]]
+name = "pandocfilters"
+version = "1.5.1"
+description = "Utilities for writing pandoc filters in python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"},
+ {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"},
+]
+
[[package]]
name = "parameterized"
version = "0.9.0"
@@ -531,6 +1027,17 @@ docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-a
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
type = ["mypy (>=1.11.2)"]
+[[package]]
+name = "pycparser"
+version = "2.22"
+description = "C parser in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
+]
+
[[package]]
name = "pydantic"
version = "2.9.2"
@@ -655,6 +1162,79 @@ files = [
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
+[[package]]
+name = "pygments"
+version = "2.18.0"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
+ {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+]
+
+[package.extras]
+windows-terminal = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "python-frontmatter"
+version = "1.1.0"
+description = "Parse and manage posts with YAML (or other) frontmatter"
+optional = false
+python-versions = "*"
+files = [
+ {file = "python-frontmatter-1.1.0.tar.gz", hash = "sha256:7118d2bd56af9149625745c58c9b51fb67e8d1294a0c76796dafdc72c36e5f6d"},
+ {file = "python_frontmatter-1.1.0-py3-none-any.whl", hash = "sha256:335465556358d9d0e6c98bbeb69b1c969f2a4a21360587b9873bfc3b213407c1"},
+]
+
+[package.dependencies]
+PyYAML = "*"
+
+[package.extras]
+docs = ["sphinx"]
+test = ["mypy", "pyaml", "pytest", "toml", "types-PyYAML", "types-toml"]
+
+[[package]]
+name = "pywin32"
+version = "308"
+description = "Python for Window Extensions"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
+ {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
+ {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"},
+ {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"},
+ {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"},
+ {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"},
+ {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"},
+ {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"},
+ {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"},
+ {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"},
+ {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"},
+ {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"},
+ {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"},
+ {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"},
+ {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"},
+ {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"},
+ {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"},
+ {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"},
+]
+
[[package]]
name = "pyyaml"
version = "6.0.2"
@@ -717,6 +1297,142 @@ files = [
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
]
+[[package]]
+name = "pyzmq"
+version = "26.2.0"
+description = "Python bindings for 0MQ"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629"},
+ {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b"},
+ {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764"},
+ {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c"},
+ {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a"},
+ {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88"},
+ {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f"},
+ {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282"},
+ {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea"},
+ {file = "pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2"},
+ {file = "pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971"},
+ {file = "pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa"},
+ {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218"},
+ {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4"},
+ {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef"},
+ {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317"},
+ {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf"},
+ {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e"},
+ {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37"},
+ {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3"},
+ {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6"},
+ {file = "pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4"},
+ {file = "pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5"},
+ {file = "pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003"},
+ {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9"},
+ {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52"},
+ {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08"},
+ {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5"},
+ {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae"},
+ {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711"},
+ {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6"},
+ {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3"},
+ {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b"},
+ {file = "pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7"},
+ {file = "pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a"},
+ {file = "pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b"},
+ {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726"},
+ {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3"},
+ {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50"},
+ {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb"},
+ {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187"},
+ {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b"},
+ {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18"},
+ {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115"},
+ {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e"},
+ {file = "pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5"},
+ {file = "pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad"},
+ {file = "pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6"},
+ {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-win32.whl", hash = "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951"},
+ {file = "pyzmq-26.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231"},
+ {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f"},
+ {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2"},
+ {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6"},
+ {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289"},
+ {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732"},
+ {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780"},
+ {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640"},
+ {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd"},
+ {file = "pyzmq-26.2.0-cp38-cp38-win32.whl", hash = "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988"},
+ {file = "pyzmq-26.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f"},
+ {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2"},
+ {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c"},
+ {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98"},
+ {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9"},
+ {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db"},
+ {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073"},
+ {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc"},
+ {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940"},
+ {file = "pyzmq-26.2.0-cp39-cp39-win32.whl", hash = "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44"},
+ {file = "pyzmq-26.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec"},
+ {file = "pyzmq-26.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb"},
+ {file = "pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072"},
+ {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1"},
+ {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d"},
+ {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca"},
+ {file = "pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c"},
+ {file = "pyzmq-26.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c"},
+ {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6"},
+ {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c"},
+ {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6"},
+ {file = "pyzmq-26.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed"},
+ {file = "pyzmq-26.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20"},
+ {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919"},
+ {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5"},
+ {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc"},
+ {file = "pyzmq-26.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4"},
+ {file = "pyzmq-26.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f"},
+ {file = "pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f"},
+]
+
+[package.dependencies]
+cffi = {version = "*", markers = "implementation_name == \"pypy\""}
+
+[[package]]
+name = "referencing"
+version = "0.35.1"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"},
+ {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
[[package]]
name = "requests"
version = "2.32.3"
@@ -738,6 +1454,129 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+[[package]]
+name = "rpds-py"
+version = "0.22.3"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"},
+ {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"},
+ {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"},
+ {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"},
+ {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"},
+ {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"},
+ {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"},
+ {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"},
+ {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"},
+ {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"},
+ {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"},
+ {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"},
+ {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"},
+ {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"},
+ {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"},
+ {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"},
+ {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"},
+ {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"},
+ {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"},
+ {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"},
+ {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"},
+ {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"},
+ {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"},
+ {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"},
+ {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"},
+ {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"},
+ {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"},
+ {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"},
+ {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"},
+ {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"},
+ {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"},
+ {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"},
+ {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"},
+ {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"},
+ {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"},
+ {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"},
+ {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"},
+ {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"},
+ {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"},
+ {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"},
+ {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"},
+ {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"},
+ {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"},
+ {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"},
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
+ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
+]
+
[[package]]
name = "sniffio"
version = "1.3.1"
@@ -749,6 +1588,35 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "soupsieve"
+version = "2.6"
+description = "A modern CSS selector implementation for Beautiful Soup."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"},
+ {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"},
+]
+
+[[package]]
+name = "tinycss2"
+version = "1.4.0"
+description = "A tiny CSS parser"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"},
+ {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"},
+]
+
+[package.dependencies]
+webencodings = ">=0.4"
+
+[package.extras]
+doc = ["sphinx", "sphinx_rtd_theme"]
+test = ["pytest", "ruff"]
+
[[package]]
name = "tokenizers"
version = "0.20.1"
@@ -866,6 +1734,26 @@ dev = ["tokenizers[testing]"]
docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"]
testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"]
+[[package]]
+name = "tornado"
+version = "6.4.2"
+description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"},
+ {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"},
+ {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"},
+ {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"},
+ {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"},
+ {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"},
+ {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"},
+ {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"},
+ {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"},
+ {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"},
+ {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"},
+]
+
[[package]]
name = "tqdm"
version = "4.66.5"
@@ -886,6 +1774,21 @@ notebook = ["ipywidgets (>=6)"]
slack = ["slack-sdk"]
telegram = ["requests"]
+[[package]]
+name = "traitlets"
+version = "5.14.3"
+description = "Traitlets Python configuration system"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
+ {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
+]
+
+[package.extras]
+docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
+test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"]
+
[[package]]
name = "types-requests"
version = "2.32.0.20241016"
@@ -928,7 +1831,18 @@ h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
+[[package]]
+name = "webencodings"
+version = "0.5.1"
+description = "Character encoding aliases for legacy web content"
+optional = false
+python-versions = "*"
+files = [
+ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
+ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
+]
+
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
-content-hash = "9f3e32193f943b04cabbcb26f2412fffadea02a184bdcee11907d419da4ce40e"
+content-hash = "6cd27e6040d352f255eb624544ad04e5577cf24a1139013a223cbd2c73b426ce"
diff --git a/pyproject.toml b/pyproject.toml
index 693342fed..b1225a999 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,6 +13,11 @@ package-mode = false
python = "^3.11"
cohere = "^5.11.1"
black = "^24.10.0"
+nbconvert = "^7.16.4"
+jinja2 = "^3.1.4"
+pyyaml = "^6.0.2"
+python-frontmatter = "^1.1.0"
+mypy = "^1.14.1"
[build-system]
diff --git a/scripts/build-cookbooks/authors.yaml b/scripts/build-cookbooks/authors.yaml
new file mode 100644
index 000000000..933458de5
--- /dev/null
+++ b/scripts/build-cookbooks/authors.yaml
@@ -0,0 +1,115 @@
+alexandrebarbet@cohere.com:
+ name: Alex Barbet
+ img: bf2c763-Alex.jpg
+
+neeral@cohere.com:
+ name: Neeral Beladia
+ img: a3689fe-Neeral.jpg
+
+harri@cohere.com:
+ name: Harri Bell-Thomas
+ img: 468e687-Harri.jpg
+
+anna@cohere.com:
+ name: Ania Bialas
+ img: c5dc5a3-Ania.jpg
+
+giannis@cohere.com:
+ name: Giannis Chatziveroglou
+ img: 73153cb-giannis.jpeg
+
+williamdarling@cohere.com:
+ name: William Darling
+ img: 7ee933d-William_Darling.jpg
+
+antoine@cohere.com:
+ name: Antoine Debugne
+ img: edbe0b1-Antoine.jpg
+
+marco@cohere.com:
+ name: Marco Del Tredici
+ img: f103c96-Marco.jpg
+
+shaan@cohere.com:
+ name: Shaan Desai
+ img: d17fc44-Shaan.jpg
+
+joan@cohere.com:
+ name: Joan Devassy
+ img: 648e4de-Kyle.jpg
+
+kyle@cohere.com:
+ name: Kyle Duffy
+ img: 648e4de-Kyle.jpg
+
+abel@cohere.com:
+ name: Abel Essiane
+ img: 7ad72f4-Abel.jpg
+
+boyu@cohere.com:
+ name: Boyu Fan
+ img: 66b2d90-boyufan.JPG.jpg
+
+utsav@cohere.com:
+ name: Utsav Garg
+ img: 9688517-Utsav.jpg
+
+jason@cohere.com:
+ name: Jason Jung
+ img: 0803e3d-Jason_Jung.jpg
+
+trushant@cohere.com:
+ name: Trushant Kalyanpur
+ img: de428e0-Trushant.jpg
+
+gokce@cohere.com:
+ name: Gokce Keskin
+ img: fe496a9-Gokce.jpg
+
+olivia@cohere.com:
+ name: Olivia Lasche
+ img: 7419032-Olivia.jpg
+
+justin@cohere.com:
+ name: Justin Lee
+ img: 3678fac-Justin.jpg
+
+katelubrano@cohere.com:
+ name: Kate Lubrano
+ img: 1131093-Kate.jpg
+
+lacey@cohere.com:
+ name: Lacey Mclear
+ img: 88c1977-Lacey.jpg
+
+vivek@cohere.com:
+ name: Vivek Mupalla
+ img: 3666c64-Vivek.jpg
+
+aal@cohere.com:
+ name: Aal Patankar
+ img: d48e622-Aal.jpg
+
+mauro@cohere.com:
+ name: Mauro Schilman
+ img: 16c3bde-Mauro.jpg
+
+sanal@cohere.com:
+ name: Sanal Shivaprasad
+ img: 811a185-Sanal.jpg
+
+anirudh@cohere.com:
+ name: Anirudh Shrinivason
+ img: e257c29-Anirudh.jpg
+
+vanessa@cohere.com:
+ name: Vanessa Tang
+ img: f6a8d8e-Vanessa.jpg
+
+jennifer@cohere.com:
+ name: Jennifer Tracey
+ img: 4579ada-Jennifer.jpg
+
+evren@cohere.com:
+ name: Evren Tumer
+ img: d69301f-Evren.jpg
diff --git a/scripts/build-cookbooks/build.py b/scripts/build-cookbooks/build.py
new file mode 100644
index 000000000..1263e1ee2
--- /dev/null
+++ b/scripts/build-cookbooks/build.py
@@ -0,0 +1,122 @@
+import yaml
+import nbformat
+from pathlib import Path
+from nbconvert import MarkdownExporter
+from jinja2 import Environment, FileSystemLoader
+import frontmatter
+import re
+from base64 import b64encode
+
+
+BASE_PATH = Path(__file__).resolve().parents[2]
+COOKBOOKS_PATH = BASE_PATH / "fern/pages/cookbooks"
+BUILD_COOKBOOKS_PATH = BASE_PATH / "scripts/build-cookbooks"
+REGISTRY_FILE = BUILD_COOKBOOKS_PATH / "registry.yaml"
+AUTHORS_FILE = BUILD_COOKBOOKS_PATH / "authors.yaml"
+TEMPLATES_PATH = BUILD_COOKBOOKS_PATH / "templates"
+MARKDOWN_IMAGE_IMPORT_PATTERN = re.compile(r"!\[(.*?)\]\((.*?)\)")
+TITLE_PATTERN = re.compile(r"(?m)^#\s.*\n", re.MULTILINE)
+SCRIPT_PATTERN = re.compile(r"", re.DOTALL)
+
+
+def _format_bytes_as_base64(data: bytes) -> str:
+ return b64encode(data).decode("utf-8")
+
+env = Environment(loader=FileSystemLoader(TEMPLATES_PATH))
+template = env.get_template('cookbook.md')
+
+def _post_process(body: str, resources: dict[str]) -> str:
+ """Perform any transformations to the generated body Markdown."""
+
+ body = re.sub(TITLE_PATTERN, "", body, count=1)
+ body = re.sub(SCRIPT_PATTERN, "", body)
+
+ # Convert the image data to base64 encoded strings
+ outputs = resources["outputs"]
+ pngs = [k for k in outputs.keys() if k.endswith(".png")]
+ png_src_dict = {
+ k: f"data:image/png;base64,{_format_bytes_as_base64(outputs[k])}" for k in pngs
+ }
+
+ # Replace markdown image links with img tags that include the appropriate base64 data
+ for k, v in png_src_dict.items():
+ body = body.replace(k, v)
+
+ # Format as img tags
+ def _sub(match):
+ alt, src = match.groups()
+ html = f'
'
+ return html
+
+ body = re.sub(MARKDOWN_IMAGE_IMPORT_PATTERN, _sub, body)
+
+ return body
+
+def build_cookbooks():
+ with open(REGISTRY_FILE, 'r') as file:
+ registry = yaml.safe_load(file)
+
+
+ # Open author metadata DB
+ with open(AUTHORS_FILE, "r") as f:
+ _authors: dict[dict] = yaml.safe_load(f)
+
+ md_exporter = MarkdownExporter()
+
+ for entry in registry:
+ if not entry.get("publish", True):
+ continue
+
+ author_email_list = entry.get("authors", list())
+ authors = [
+ dict(
+ name=_authors[email]["name"],
+ img=_authors[email]["img"],
+ email=email,
+ )
+ for email in author_email_list
+ if email in _authors
+ ]
+
+ notebook_path = BASE_PATH / entry["path"]
+ with open(notebook_path, 'r') as f:
+ notebook_content = nbformat.read(f, as_version=4)
+ body, resources = md_exporter.from_notebook_node(notebook_content)
+
+ # Post-process content
+ body = _post_process(body, resources)
+
+ slug = f"/page/{entry['slug']}"
+ output_file_path = COOKBOOKS_PATH / f"{entry['slug']}.mdx"
+
+ if output_file_path.exists():
+ with open(output_file_path, 'r', encoding='utf-8') as file:
+ post = frontmatter.load(file)
+ existing_metadata = post.metadata
+ else:
+ existing_metadata = {}
+
+ # Prepare data for rendering the template
+ body_data = {
+ 'title': entry.get('title', existing_metadata.get('title', 'Default Title')),
+ 'slug': slug,
+ 'description': entry.get('description', existing_metadata.get('description', '')),
+ 'image': entry.get('image', existing_metadata.get('image', '')),
+ 'keywords': entry.get('keywords', existing_metadata.get('keywords', '')),
+ 'body': body,
+ 'authors': authors,
+ 'cookbook_path': entry.get('path', '')
+ }
+
+ # Render the template with the data
+ content = template.render(body_data)
+
+ # Ensure the directory exists
+ output_file_path.parent.mkdir(parents=True, exist_ok=True)
+
+ # Write to file
+ with open(output_file_path, 'w', encoding='utf-8') as file:
+ file.write(content)
+
+if __name__ == "__main__":
+ build_cookbooks()
diff --git a/scripts/build-cookbooks/registry.yaml b/scripts/build-cookbooks/registry.yaml
new file mode 100644
index 000000000..015f4ef61
--- /dev/null
+++ b/scripts/build-cookbooks/registry.yaml
@@ -0,0 +1,437 @@
+## Agents
+- title: Calendar Agent with Native Multi Step Tool
+ path: notebooks/agents/Tool_Use.ipynb
+ slug: calendar-agent
+ blurb: A minimal working example of how to use our chat API to call tools.
+ tags:
+ - agents
+
+- title: Basic Tool Use
+ path: notebooks/agents/Vanilla_Tool_Use.ipynb
+ slug: basic-tool-use
+ blurb:
+ Connect large language models to external tools, like search engines, APIs,
+ and databases, to access and utilise a wider range of data.
+ tags:
+ - agents
+
+- title: Multi-Step Tool Use
+ path: notebooks/agents/Vanilla_Multi_Step_Tool_Use.ipynb
+ slug: basic-multi-step
+ blurb:
+ Multi-step tool use allows developers to connect Cohere's models to external
+ tools like search engines, APIs, and databases.
+ tags:
+ - agents
+ - oss
+
+- title: A ReAct Agent with Command R+, Achieving The Same Goals as Adaptive RAG
+ path: notebooks/react_agent_adaptive_rag_cohere.ipynb
+ slug: adaptive-rag-agent
+ blurb:
+ An example of using Command R+ to create an agent that can search the web,
+ retrieve info from a vector store, and self-reflect.
+ tags:
+ - agents
+ - rag
+ publish: false
+
+- title: A Data Analyst Agent Built with Cohere and Langchain
+ path: notebooks/agents/Data_Analyst_Agent_Cohere_and_Langchain.ipynb
+ slug: data-analyst-agent
+ blurb: Build a data analyst agent with Python and Cohere's Command R+ mode and Langchain.
+ tags:
+ - agents
+ - oss
+
+- title: Short-Term Memory Handling for Agents
+ path: notebooks/agents/agent_memory_walkthrough.ipynb
+ slug: agent-short-term-memory
+ blurb: A walkthrough of how to use Langchain cohere_react_agent to effectively manage short-term chat history that contains tool calls with Langchain.
+ tags:
+ - agents
+ authors:
+ - marco@cohere.com
+
+- title: Agent API Calls
+ path: notebooks/agents/agents_with_deterministic_functions.ipynb
+ slug: agent-api-calls
+ blurb: A walkthrough of how to use Langchain cohere_react_agent to make API calls to external services that require regex.
+ tags:
+ - agents
+ authors:
+ - marco@cohere.com
+
+- title: Financial CSV Agent with Langchain
+ path: notebooks/agents/financial-csv-agent/financial_csv_publication.ipynb
+ slug: csv-agent
+ blurb: The notebook demonstrates how to setup a Langchain Cohere ReAct Agent to answer questions over the income statement and balance sheet from Apple's SEC10K 2020 form.
+ tags:
+ - agents
+ - oss
+ authors:
+ - shaan@cohere.com
+
+- title: Agentic RAG for PDFs with mixed data
+ path: notebooks/agents/agentic-RAG/agentic_rag_langchain.ipynb
+ slug: agentic-rag-mixed-data
+ blurb: A walkthrough of how to use Langchain cohere_react_agent to run RAG as an agent tool to handle PDFs with mixed table and text data.
+ tags:
+ - agents
+ authors:
+ - shaan@cohere.com
+
+- title: SQL Agent
+ path: notebooks/agents/sql_agent/sql_agent.ipynb
+ slug: sql-agent
+ blurb: In this notebook we explore how to setup a Cohere ReAct Agent to answer questions over SQL Databases using Langchain's SQLDBToolkit.
+ tags:
+ - agents
+ authors:
+ - shaan@cohere.com
+
+- title: Financial CSV Agent with Native Multi-Step Cohere API
+ path: notebooks/agents/financial-csv-agent/financial_csv_publication_native.ipynb
+ slug: csv-agent-native-api
+ blurb: This notebook demonstrates how to setup a Cohere Native API sequence of tool calls to answer questions over the income statement and balance sheet from Apple's SEC10K 2020 form.
+ tags:
+ - agents
+ authors:
+ - jason@cohere.com
+
+- title:
+ A ReAct Agent with Command R+, Achieving The Same Goals as Adaptive RAG Using
+ Custom Tools
+ path: notebooks/agents/Multi_Step_Tool_Use.ipynb
+ slug: multi-step-custom-tools
+ blurb:
+ A guide to building a ReAct agent with Command R+ for web search, RAG retrieval,
+ and custom tools.
+ tags:
+ - agents
+ - rag
+ publish: false
+
+- title: PDF Extractor with Native Multi Step Tool Use
+ path: notebooks/agents/pdf-extractor/pdf_extractor.ipynb
+ slug: pdf-extractor
+ blurb: How we can leverage agents to extract information from PDFs?
+ tags:
+ - agents
+ authors:
+ - jason@cohere.com
+
+- title: Agentic Multi-Stage RAG with Cohere Tools API
+ path: notebooks/agents/agentic-RAG/agentic_multi_stage_rag_native.ipynb
+ slug: agentic-multi-stage-rag
+ blurb: How to use Agents to improve RAG performance.
+ tags:
+ - agents
+ authors:
+ - jason@cohere.com
+
+- title: Agentic RAG with an Evaluator, Web Search, Human Input, and Python Tool.
+ path: notebooks/agents/agentic-RAG/multi_purpose_agent.ipynb
+ slug: multi-purpose-agent
+ blurb: How to incorporate multiple databases, tools, and human feedback into agentic RAG.
+ tags:
+ - agents
+ authors:
+ - jason@cohere.com
+
+## Other
+- title: Using Redis with Cohere
+ path: notebooks/Cohere_Redis_Guide.ipynb
+ slug: redis-guide
+ blurb:
+ Learn how to use Cohere's text vectorizer with Redis to create a semantic
+ search index.
+ tags:
+ - cloud
+ - search
+ publish: false
+
+- title: Wikipedia Semantic Search with Cohere Embedding Archives
+ path: notebooks/Wikipedia_Semantic_Search_With_Cohere_Embeddings_Archives.ipynb
+ slug: wikipedia-semantic-search
+ blurb: Find relevant Wikipedia passages with semantic search and Cohere embeddings.
+ tags:
+ - search
+
+- title: Semantic Search with Cohere Embed Jobs and Pinecone serverless Solution
+ path: notebooks/Embed_Jobs_Serverless_Pinecone_Semantic_Search.ipynb
+ slug: embed-jobs-serverless-pinecone
+ blurb:
+ Learn how to use Cohere's Embed Jobs and Pinecone's serverless solution to
+ perform semantic search.
+ tags:
+ - cloud
+ - search
+
+- title: Basic RAG
+ path: notebooks/Vanilla_RAG.ipynb
+ slug: basic-rag
+ blurb:
+ RAG boosts the accuracy of language models by combining them with a retrieval
+ system.
+ tags:
+ - rag
+
+- title: End-to-end RAG using Elasticsearch and Cohere
+ path: notebooks/Cohere_Elastic_Guide.ipynb
+ slug: elasticsearch-and-cohere
+ blurb:
+ Learn how to use Cohere and Elastic for semantic search and retrieval-augmented
+ generation.
+ tags:
+ - search
+ - rag
+ - cloud
+
+- title: Semantic Search with Cohere Embed Jobs
+ path: notebooks/Embed_Jobs_Semantic_Search.ipynb
+ slug: embed-jobs
+ blurb: Learn how to use Cohere Embed Jobs to create semantic search functionality.
+ tags:
+ - search
+
+- title: Fueling Generative Content with Keyword Research
+ path: notebooks/guides/Fueling_Generative_Content_with_Keyword_Research.ipynb
+ slug: fueling-generative-content
+ blurb:
+ Enhance content creation with keyword-based topic clusters, generating blog
+ ideas with Cohere's Chat model.
+
+- title: Chunking Strategies
+ path: notebooks/guides/Chunking_strategies.ipynb
+ slug: chunking-strategies
+ blurb: Explore chunking strategies for RAG systems.
+ tags:
+ - rag
+ authors:
+ - anna@cohere.com
+
+- title: Text Classification Using Embeddings
+ path: notebooks/guides/Text_Classification_Using_Embeddings.ipynb
+ slug: text-classification-using-embeddings
+ blurb:
+ Build a text classifier with Cohere embeddings. This notebook shows you how
+ to train a sentiment analysis model with a small dataset.
+
+- title: Recipes for Better Meeting Notes
+ path: notebooks/guides/Recipes_for_better_meeting_notes_summary.ipynb
+ slug: recipes-for-meeting-notes
+ blurb:
+ Learn how to use Command to auto-generate meeting summaries, focusing on
+ action items, speaker perspectives, and specific topics.
+ tags:
+ - summarization
+ publish: false
+
+- title: Analysis of Form 10-K/10-Q Using Cohere and RAG
+ path: notebooks/guides/Analysis_of_Form_10_K_Using_Cohere_and_RAG.ipynb
+ slug: analysis-of-financial-forms
+ blurb:
+ Jumpstart financial analysis of 10-Ks or 10-Qs with Cohere's Command model
+ and LlamaIndex tooling.
+ tags:
+ - summarization
+ authors:
+ - alexandrebarbet@cohere.com
+
+- title:
+ Question Answering using LangChain and Cohere's Generate and Embedding Models
+ from SageMaker JumpStart
+ path: notebooks/guides/QuestionAnwering_Cohere_SagemakerJumpstart.ipynb
+ slug: sagemaker-question-answering
+ blurb: Use Cohere's LLMs with SageMaker to build a question-answering app.
+ tags:
+ - cloud
+ - oss
+ publish: false
+
+- title: Article Recommender with Text Embedding Classification Extraction
+ path: notebooks/guides/Article_Recommender_with_Text_Embedding_Classification_Extraction.ipynb
+ slug: article-recommender-with-text-embeddings
+ blurb:
+ Improve news article recommendations with embeddings, text classification,
+ and keyword extraction.
+
+- title: Migrating Monolithic Prompts to Command-R with RAG
+ path: notebooks/guides/Migrating_Monolithic_Prompts_to_Command_R_with_RAG.ipynb
+ slug: migrating-prompts
+ blurb:
+ Command-R simplifies prompt migration to RAG, reducing hallucination and
+ improving conciseness and grounding.
+ tags:
+ - rag
+
+- title: Basic Semantic Search
+ path: notebooks/guides/Basic_Semantic_Search.ipynb
+ slug: basic-semantic-search
+ blurb: Learn how to build a simple semantic search engine using sentence embeddings.
+ tags:
+ - search
+
+- title: Using Generation Models for Summarization
+ path: notebooks/guides/Basic_Summarization_Notebook.ipynb
+ slug: basic-summarization
+ blurb:
+ Learn how to use generation models to summarize text with Cohere's Python
+ SDK.
+ tags:
+ - summarization
+ publish: false
+
+- title: Long Form General Strategies
+ path: notebooks/guides/Long_form_General_Strategies.ipynb
+ slug: long-form-general-strategies
+ blurb: Techniques to address lengthy documents exceeding the context window of LLMs.
+ tags:
+ - summarization
+ authors:
+ - anna@cohere.com
+
+- title: Summarization Evals
+ path: notebooks/guides/Summarization_Evals.ipynb
+ slug: summarization-evals
+ blurb:
+ This cookbook demonstrates an approach to evaluating summarization tasks
+ using LLM evaluation.
+ tags:
+ - summarization
+
+- title: Multilingual Search with Cohere and Langchain
+ path: notebooks/guides/Multilingual_Search_with_Cohere_and_Langchain.ipynb
+ slug: multilingual-search
+ blurb: Multilingual search with Cohere and Langchain.
+ tags:
+ - search
+ - oss
+
+- title: Advanced Document Parsing For Enterprises
+ path: notebooks/guides/Document_Parsing_For_Enterprises.ipynb
+ slug: document-parsing-for-enterprises
+ blurb: Learn how to parse PDFs into text with a real-world example.
+ authors:
+ - giannis@cohere.com
+ - justin@cohere.com
+
+- title: Summarizing Meeting Notes
+ path: notebooks/guides/Meeting_Summaries_General_&_LangChain.ipynb
+ slug: summarizing-meeting-notes
+ blurb:
+ Learn how to use Cohere's Command-R model for summarization with this comprehensive
+ guide.
+ tags:
+ - summarization
+ publish: false
+
+- title: Generating Stories and Story ideas with Cohere and Stable Diffusion
+ path: notebooks/guides/Generating_stories_with_LLMs_and_Stable_Diffusion.ipynb
+ slug: generating-stories
+ blurb: This notebook teaches users how to generate sci-fi stories using AI.
+ publish: false
+
+- title: Wikipedia Semantic Search with Cohere + Weaviate
+ path: notebooks/guides/Wikipedia_search_demo_cohere_weaviate.ipynb
+ slug: wikipedia-search-with-weaviate
+ blurb:
+ Search 10 million Wikipedia vectors with Cohere's multilingual model and
+ Weaviate's public dataset.
+ tags:
+ - search
+
+- title: Brainstorming Story Ideas with Cohere and Stable Diffusion
+ path: notebooks/guides/Brainstorming_Story_Ideas_with_Cohere_and_Stable_Diffusion.ipynb
+ slug: brainstorming-story-ideas
+ blurb:
+ Two hackers, suspected of stealing Bitcoin, must prove their innocence to
+ a cyber intelligence agent.
+ publish: false
+
+- title: RAG With Chat Embed and Rerank via Pinecone
+ path: notebooks/guides/RAG_with_Chat_Embed_and_Rerank_via_Pinecone.ipynb
+ slug: rag-with-chat-embed
+ blurb:
+ This notebook shows how to build a RAG-powered chatbot with Cohere's Chat
+ endpoint.
+ tags:
+ - rag
+
+- title: Creating a QA Bot From Technical Documentation
+ path: notebooks/guides/Creating_a_QA_bot_from_technical_documentation.ipynb
+ slug: creating-a-qa-bot
+ blurb:
+ Create a chatbot that answers user questions based on technical documentation
+ using Cohere embeddings and LlamaIndex.
+ tags:
+ - oss
+ - search
+ - rag
+
+- title: "Pondr, Fostering Connection through Good Conversation"
+ path: notebooks/guides/Pondr_Question_Generation.ipynb
+ slug: pondr
+ blurb:
+ Learn how to create Pondr, a game that fosters connections and meaningful
+ conversations with friends and strangers.
+
+- title: Demo of Rerank
+ path: notebooks/guides/rerank-demo.ipynb
+ slug: rerank-demo
+ blurb:
+ Improve search results with Cohere's Relevance Endpoint, which reranks documents
+ for better accuracy.
+ tags:
+ - search
+
+- title: Hello World! Meet Language AI
+ path: notebooks/guides/Hello_World_Meet_Language_AI.ipynb
+ slug: hello-world-meet-ai
+ blurb: General quickstart with basic instructions on how to get started with generative AI.
+
+- title: Entity Extraction with Generative Models
+ path: notebooks/guides/Entity_Extrcation_with_Generative_Language_Models.ipynb
+ slug: entity-extraction
+ blurb:
+ Learn how to extract named entities from text using Cohere's generative models
+ and Python.
+ publish: false
+
+- title: Three Ways to Build a Text Classifier with Cohere.ipynb
+ path: notebooks/guides/Three_Ways_to_Build_a_Text_Classifier_with_Cohere.ipynb
+ slug: ways-to-build-a-text-classifier-with-cohere
+ blurb:
+ Learn three ways to build a text classifier with Cohere's API, from few-shot
+ to finetuning.
+ publish: false
+
+- title: Topic Modeling AI Papers
+ path: notebooks/guides/Topic_Modeling_AI_Papers.ipynb
+ slug: topic-modeling-ai-papers
+ blurb: Learn how to build a topic modeling pipeline in Python.
+
+- title: Grounded Summarization Using Command R
+ path: notebooks/guides/Grounded_summarisation_using_Command_R.ipynb
+ slug: grounded-summarization
+ blurb:
+ Learn how to summarise long documents with citations, reducing cost and improving
+ latency.
+ tags:
+ - summarization
+
+- title: Deep Dive Into RAG Evaluation
+ path: notebooks/guides/Deep_dive_into_RAG_evaluation.ipynb
+ slug: rag-evaluation-deep-dive
+ blurb: Learn how to evaluate RAG models.
+ tags:
+ - rag
+ authors:
+ - marco@cohere.com
+ - aal@cohere.com
+
+- title: Analyzing Hacker News with Six Language Understanding Methods
+ path: notebooks/guides/Analyzing_Hacker_News_with_Six_Language_Understanding_Methods.ipynb
+ slug: analyzing-hacker-news
+ blurb: Learn how to analyze textual data using Cohere's tools.
diff --git a/scripts/build-cookbooks/templates/cookbook.md b/scripts/build-cookbooks/templates/cookbook.md
new file mode 100644
index 000000000..8dadf12cd
--- /dev/null
+++ b/scripts/build-cookbooks/templates/cookbook.md
@@ -0,0 +1,28 @@
+---
+title: {{ title }}
+slug: {{ slug }}
+
+description: "{{ description }}"
+image: "{{ image }}"
+keywords: "{{ keywords }}"
+---
+
+import { AuthorsContainer } from "../../components/authors-container";
+import { CookbookHeader } from "../../components/cookbook-header";
+
+{% if authors -%}
+
+{% endif %}
+
+
+
+{{ body }}