{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "683953b3",
   "metadata": {},
   "source": [
    "# Chroma\n",
    "\n",
    ">[Chroma](https://docs.trychroma.com/getting-started) is a AI-native open-source vector database focused on developer productivity and happiness. Chroma is licensed under Apache 2.0.\n",
    "\n",
    "\n",
    "Install Chroma with:\n",
    "\n",
    "```sh\n",
    "pip install chromadb\n",
    "```\n",
    "\n",
    "Chroma runs in various modes. See below for examples of each integrated with LangChain.\n",
    "- `in-memory` - in a python script or jupyter notebook\n",
    "- `in-memory with persistance` - in a script or notebook and save/load to disk\n",
    "- `in a docker container` - as a server running your local machine or in the cloud\n",
    "\n",
    "Like any other database, you can: \n",
    "- `.add` \n",
    "- `.get` \n",
    "- `.update`\n",
    "- `.upsert`\n",
    "- `.delete`\n",
    "- `.peek`\n",
    "- and `.query` runs the similarity search.\n",
    "\n",
    "View full docs at [docs](https://docs.trychroma.com/reference/Collection). To access these methods directly, you can do `._collection_.method()`\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b5ffbf8",
   "metadata": {},
   "source": [
    "## Basic Example\n",
    "\n",
    "In this basic example, we take the most recent State of the Union Address, split it into chunks, embed it using an open-source embedding model, load it into Chroma, and then query it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ae9fcf3e",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using embedded DuckDB without persistence: data will be transient\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
      "\n",
      "Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
      "\n",
      "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
      "\n",
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
     ]
    }
   ],
   "source": [
    "# import\n",
    "from langchain.embeddings.sentence_transformer import SentenceTransformerEmbeddings\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.vectorstores import Chroma\n",
    "from langchain.document_loaders import TextLoader\n",
    "\n",
    "# load the document and split it into chunks\n",
    "loader = TextLoader(\"../../../state_of_the_union.txt\")\n",
    "documents = loader.load()\n",
    "\n",
    "# split it into chunks\n",
    "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n",
    "docs = text_splitter.split_documents(documents)\n",
    "\n",
    "# create the open-source embedding function\n",
    "embedding_function = SentenceTransformerEmbeddings(model_name=\"all-MiniLM-L6-v2\")\n",
    "\n",
    "# load it into Chroma\n",
    "db = Chroma.from_documents(docs, embedding_function)\n",
    "\n",
    "# query it\n",
    "query = \"What did the president say about Ketanji Brown Jackson\"\n",
    "docs = db.similarity_search(query)\n",
    "\n",
    "# print results\n",
    "print(docs[0].page_content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c9a11cc",
   "metadata": {},
   "source": [
    "## Basic Example (including saving to disk)\n",
    "\n",
    "Extending the previous example, if you want to save to disk, simply initialize the Chroma client and pass the directory where you want the data to be saved to. \n",
    "\n",
    "`Caution`: Chroma makes a best-effort to automatically save data to disk, however multiple in-memory clients can stomp each other's work. As a best practice, only have one client per path running at any given time.\n",
    "\n",
    "`Protip`: Sometimes you can call `db.persist()` to force a save. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "49f9bd49",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using embedded DuckDB with persistence: data will be stored in: ./chroma_db\n",
      "Using embedded DuckDB with persistence: data will be stored in: ./chroma_db\n",
      "No embedding_function provided, using default embedding function: SentenceTransformerEmbeddingFunction\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
      "\n",
      "Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
      "\n",
      "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
      "\n",
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
     ]
    }
   ],
   "source": [
    "# save to disk\n",
    "db2 = Chroma.from_documents(docs, embedding_function, persist_directory=\"./chroma_db\")\n",
    "db2.persist()\n",
    "docs = db.similarity_search(query)\n",
    "\n",
    "# load from disk\n",
    "db3 = Chroma(persist_directory=\"./chroma_db\")\n",
    "docs = db.similarity_search(query)\n",
    "print(docs[0].page_content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9cf6d70",
   "metadata": {},
   "source": [
    "## Basic Example (using the Docker Container)\n",
    "\n",
    "You can also run the Chroma Server in a Docker container separately, create a Client to connect to it, and then pass that to LangChain. \n",
    "\n",
    "Chroma has the ability to handle multiple `Collections` of documents, but the LangChain interface expects one, so we need to specify the collection name. The default collection name used by LangChain is \"langchain\".\n",
    "\n",
    "Here is how to clone, build, and run the Docker Image:\n",
    "```\n",
    "git clone git@github.com:chroma-core/chroma.git\n",
    "docker-compose up -d --build\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "74aee70e",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "No embedding_function provided, using default embedding function: SentenceTransformerEmbeddingFunction\n",
      "No embedding_function provided, using default embedding function: SentenceTransformerEmbeddingFunction\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
      "\n",
      "Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
      "\n",
      "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
      "\n",
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
     ]
    }
   ],
   "source": [
    "# create the chroma client\n",
    "import chromadb\n",
    "import uuid\n",
    "from chromadb.config import Settings\n",
    "client = chromadb.Client(Settings(chroma_api_impl=\"rest\",\n",
    "                                        chroma_server_host=\"localhost\",\n",
    "                                        chroma_server_http_port=\"8000\"\n",
    "                                    ))\n",
    "client.reset() # resets the database\n",
    "collection = client.create_collection(\"my_collection\")\n",
    "for doc in docs:\n",
    "    collection.add(ids=[str(uuid.uuid1())], metadatas=doc.metadata, documents=doc.page_content)\n",
    "\n",
    "# tell LangChain to use our client and collection name\n",
    "db4 = Chroma(client=client, collection_name=\"my_collection\")\n",
    "docs = db.similarity_search(query)\n",
    "print(docs[0].page_content)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9ed3ec50",
   "metadata": {},
   "source": [
    "## Update and Delete\n",
    "\n",
    "While building toward a real application, you want to go beyond adding data, and also update and delete data. \n",
    "\n",
    "Chroma has users provide `ids` to simplify the bookkeeping here. `ids` can be the name of the file, or a combined has like `filename_paragraphNumber`, etc.\n",
    "\n",
    "Chroma supports all these operations - though some of them are still being integrated all the way through the LangChain interface. Additional workflow improvements will be added soon.\n",
    "\n",
    "Here is a basic example showing how to do various operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "81a02810",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using embedded DuckDB without persistence: data will be transient\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'source': '../../../state_of_the_union.txt', 'new_value': 'hello world'}\n",
      "{'ids': ['1'], 'embeddings': None, 'documents': ['Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.'], 'metadatas': [{'source': '../../../state_of_the_union.txt', 'new_value': 'hello world'}]}\n",
      "count before 4\n",
      "count after 3\n"
     ]
    }
   ],
   "source": [
    "# create simple ids\n",
    "ids = [str(i) for i in range(1, len(docs)+1)]\n",
    "\n",
    "# add data\n",
    "example_db = Chroma.from_documents(docs, embedding_function, ids=ids)\n",
    "docs = example_db.similarity_search(query)\n",
    "print(docs[0].metadata)\n",
    "\n",
    "# update the metadata for a document\n",
    "docs[0].metadata = {'source': '../../../state_of_the_union.txt', 'new_value': 'hello world'}\n",
    "example_db.update_document(ids[0], docs[0])\n",
    "print(example_db._collection.get(ids=[ids[0]]))\n",
    "\n",
    "# delete the last document\n",
    "print(\"count before\", example_db._collection.count())\n",
    "example_db._collection.delete(ids=[ids[-1]])\n",
    "print(\"count after\", example_db._collection.count())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac6bc71a",
   "metadata": {},
   "source": [
    "## Use OpenAI Embeddings\n",
    "\n",
    "Many people like to use OpenAIEmbeddings, here is how to set that up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "42080f37-8fd1-4cec-acd9-15d2b03b2f4d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# get a token: https://platform.openai.com/account/api-keys\n",
    "\n",
    "from getpass import getpass\n",
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "\n",
    "OPENAI_API_KEY = getpass()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "c7a94d6c-b4d4-4498-9bdd-eb50c92b85c5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "5eabdb75",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using embedded DuckDB without persistence: data will be transient\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n",
      "\n",
      "Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n",
      "\n",
      "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n",
      "\n",
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
     ]
    }
   ],
   "source": [
    "embeddings = OpenAIEmbeddings()\n",
    "db5 = Chroma.from_documents(docs, embeddings)\n",
    "\n",
    "query = \"What did the president say about Ketanji Brown Jackson\"\n",
    "docs = db.similarity_search(query)\n",
    "print(docs[0].page_content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d9c28ad",
   "metadata": {},
   "source": [
    "***\n",
    "\n",
    "## Other Information"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18152965",
   "metadata": {},
   "source": [
    "### Similarity search with score"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "346347d7",
   "metadata": {},
   "source": [
    "The returned distance score is cosine distance. Therefore, a lower score is better."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "72aaa9c8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "docs = db.similarity_search_with_score(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d88e958e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../../state_of_the_union.txt'}),\n",
       " 0.3949805498123169)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "794a7552",
   "metadata": {},
   "source": [
    "### Retriever options\n",
    "\n",
    "This section goes over different options for how to use Chroma as a retriever.\n",
    "\n",
    "#### MMR\n",
    "\n",
    "In addition to using similarity search in the retriever object, you can also use `mmr`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "96ff911a",
   "metadata": {},
   "outputs": [],
   "source": [
    "retriever = db.as_retriever(search_type=\"mmr\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f00be6d0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../../state_of_the_union.txt'})"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "retriever.get_relevant_documents(query)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "275dbd0a",
   "metadata": {},
   "source": [
    "### Filtering on metadata\n",
    "\n",
    "It can be helpful to narrow down the collection before working with it.\n",
    "\n",
    "For example, collections can be filtered on metadata using the get method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "a5119221",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'source': 'some_other_source'}\n",
      "{'ids': ['1'], 'embeddings': None, 'documents': ['Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.'], 'metadatas': [{'source': 'some_other_source'}]}\n"
     ]
    }
   ],
   "source": [
    "# create simple ids\n",
    "ids = [str(i) for i in range(1, len(docs) + 1)]\n",
    "\n",
    "# add data\n",
    "example_db = Chroma.from_documents(docs, embedding_function, ids=ids)\n",
    "docs = example_db.similarity_search(query)\n",
    "print(docs[0].metadata)\n",
    "\n",
    "# update the source for a document\n",
    "docs[0].metadata = {\"source\": \"some_other_source\"}\n",
    "example_db.update_document(ids[0], docs[0])\n",
    "print(example_db._collection.get(ids=[ids[0]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "81600dc1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ids': ['1'],\n",
       " 'embeddings': None,\n",
       " 'documents': ['Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \\n\\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \\n\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\n\\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.'],\n",
       " 'metadatas': [{'source': 'some_other_source'}]}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# filter collection for updated source\n",
    "example_db.get(where={\"source\": \"some_other_source\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
