diff --git a/docs/chat_message_history.ipynb b/docs/chat_message_history.ipynb index 02e6f04f..c7f37933 100644 --- a/docs/chat_message_history.ipynb +++ b/docs/chat_message_history.ipynb @@ -1,581 +1,587 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "f22eab3f84cbeb37", - "metadata": { - "id": "f22eab3f84cbeb37" - }, - "source": [ - "# Google Cloud SQL for PostgreSQL\n", - "\n", - "> [Cloud SQL](https://cloud.google.com/sql) is a fully managed relational database service that offers high performance, seamless integration, and impressive scalability. It offers MySQL, PostgreSQL, and SQL Server database engines. Extend your database application to build AI-powered experiences leveraging Cloud SQL's Langchain integrations.\n", - "\n", - "This notebook goes over how to use `Cloud SQL for PostgreSQL` to store chat message history with the `PostgresChatMessageHistory` class.\n", - "\n", - "Learn more about the package on [GitHub](https://github.com/googleapis/langchain-google-cloud-sql-pg-python/).\n", - "\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/googleapis/langchain-google-cloud-sql-pg-python/blob/main/docs/chat_message_history.ipynb)" - ] - }, - { - "cell_type": "markdown", - "id": "da400c79-a360-43e2-be60-401fd02b2819", - "metadata": { - "id": "da400c79-a360-43e2-be60-401fd02b2819" - }, - "source": [ - "## Before You Begin\n", - "\n", - "To run this notebook, you will need to do the following:\n", - "\n", - " * [Create a Google Cloud Project](https://developers.google.com/workspace/guides/create-project)\n", - " * [Enable the Cloud SQL Admin API.](https://console.cloud.google.com/marketplace/product/google/sqladmin.googleapis.com)\n", - " * [Create a Cloud SQL for PostgreSQL instance](https://cloud.google.com/sql/docs/postgres/create-instance)\n", - " * [Create a Cloud SQL database](https://cloud.google.com/sql/docs/mysql/create-manage-databases)\n", - " * [Add an IAM database user to the database](https://cloud.google.com/sql/docs/postgres/add-manage-iam-users#creating-a-database-user) (Optional)" - ] - }, - { - "cell_type": "markdown", - "id": "Mm7-fG_LltD7", - "metadata": { - "id": "Mm7-fG_LltD7" - }, - "source": [ - "### 🦜🔗 Library Installation\n", - "The integration lives in its own `langchain-google-cloud-sql-pg` package, so we need to install it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1VELXvcj8AId", - "metadata": { - "id": "1VELXvcj8AId" - }, - "outputs": [], - "source": [ - "%pip install --upgrade --quiet langchain-google-cloud-sql-pg langchain-google-vertexai" - ] - }, - { - "cell_type": "markdown", - "id": "98TVoM3MNDHu", - "metadata": { - "id": "98TVoM3MNDHu" - }, - "source": [ - "**Colab only:** Uncomment the following cell to restart the kernel or use the button to restart the kernel. For Vertex AI Workbench you can restart the terminal using the button on top." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "v6jBDnYnNM08", - "metadata": { - "id": "v6jBDnYnNM08" - }, - "outputs": [], - "source": [ - "# # Automatically restart kernel after installs so that your environment can access the new packages\n", - "# import IPython\n", - "\n", - "# app = IPython.Application.instance()\n", - "# app.kernel.do_shutdown(True)" - ] - }, - { - "cell_type": "markdown", - "id": "yygMe6rPWxHS", - "metadata": { - "id": "yygMe6rPWxHS" - }, - "source": [ - "### 🔐 Authentication\n", - "Authenticate to Google Cloud as the IAM user logged into this notebook in order to access your Google Cloud Project.\n", - "\n", - "* If you are using Colab to run this notebook, use the cell below and continue.\n", - "* If you are using Vertex AI Workbench, check out the setup instructions [here](https://github.com/GoogleCloudPlatform/generative-ai/tree/main/setup-env)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "PTXN1_DSXj2b", - "metadata": { - "id": "PTXN1_DSXj2b" - }, - "outputs": [], - "source": [ - "from google.colab import auth\n", - "\n", - "auth.authenticate_user()" - ] - }, - { - "cell_type": "markdown", - "id": "NEvB9BoLEulY", - "metadata": { - "id": "NEvB9BoLEulY" - }, - "source": [ - "### ☁ Set Your Google Cloud Project\n", - "Set your Google Cloud project so that you can leverage Google Cloud resources within this notebook.\n", - "\n", - "If you don't know your project ID, try the following:\n", - "\n", - "* Run `gcloud config list`.\n", - "* Run `gcloud projects list`.\n", - "* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "gfkS3yVRE4_W", - "metadata": { - "cellView": "form", - "id": "gfkS3yVRE4_W" - }, - "outputs": [], - "source": [ - "# @markdown Please fill in the value below with your Google Cloud project ID and then run the cell.\n", - "\n", - "PROJECT_ID = \"my-project-id\" # @param {type:\"string\"}\n", - "\n", - "# Set the project id\n", - "!gcloud config set project {PROJECT_ID}" - ] - }, - { - "cell_type": "markdown", - "id": "rEWWNoNnKOgq", - "metadata": { - "id": "rEWWNoNnKOgq" - }, - "source": [ - "### 💡 API Enablement\n", - "The `langchain-google-cloud-sql-pg` package requires that you [enable the Cloud SQL Admin API](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin.googleapis.com) in your Google Cloud Project." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "5utKIdq7KYi5", - "metadata": { - "id": "5utKIdq7KYi5" - }, - "outputs": [], - "source": [ - "# enable Cloud SQL Admin API\n", - "!gcloud services enable sqladmin.googleapis.com" - ] - }, - { - "cell_type": "markdown", - "id": "f8f2830ee9ca1e01", - "metadata": { - "id": "f8f2830ee9ca1e01" - }, - "source": [ - "## Basic Usage" - ] - }, - { - "cell_type": "markdown", - "id": "OMvzMWRrR6n7", - "metadata": { - "id": "OMvzMWRrR6n7" - }, - "source": [ - "### Set Cloud SQL database values\n", - "Find your database values, in the [Cloud SQL Instances page](https://console.cloud.google.com/sql?_ga=2.223735448.2062268965.1707700487-2088871159.1707257687)." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "irl7eMFnSPZr", - "metadata": { - "id": "irl7eMFnSPZr" - }, - "outputs": [], - "source": [ - "# @title Set Your Values Here { display-mode: \"form\" }\n", - "REGION = \"us-central1\" # @param {type: \"string\"}\n", - "INSTANCE = \"my-postgresql-instance\" # @param {type: \"string\"}\n", - "DATABASE = \"my-database\" # @param {type: \"string\"}\n", - "TABLE_NAME = \"message_store\" # @param {type: \"string\"}" - ] - }, - { - "cell_type": "markdown", - "id": "QuQigs4UoFQ2", - "metadata": { - "id": "QuQigs4UoFQ2" - }, - "source": [ - "### PostgresEngine Connection Pool\n", - "\n", - "One of the requirements and arguments to establish Cloud SQL as a ChatMessageHistory memory store is a `PostgresEngine` object. The `PostgresEngine` configures a connection pool to your Cloud SQL database, enabling successful connections from your application and following industry best practices.\n", - "\n", - "To create a `PostgresEngine` using `PostgresEngine.from_instance()` you need to provide only 4 things:\n", - "\n", - "1. `project_id` : Project ID of the Google Cloud Project where the Cloud SQL instance is located.\n", - "1. `region` : Region where the Cloud SQL instance is located.\n", - "1. `instance` : The name of the Cloud SQL instance.\n", - "1. `database` : The name of the database to connect to on the Cloud SQL instance.\n", - "\n", - "By default, [IAM database authentication](https://cloud.google.com/sql/docs/postgres/iam-authentication#iam-db-auth) will be used as the method of database authentication. This library uses the IAM principal belonging to the [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/application-default-credentials) sourced from the envionment.\n", - "\n", - "For more informatin on IAM database authentication please see:\n", - "* [Configure an instance for IAM database authentication](https://cloud.google.com/sql/docs/postgres/create-edit-iam-instances)\n", - "* [Manage users with IAM database authentication](https://cloud.google.com/sql/docs/postgres/add-manage-iam-users)\n", - "\n", - "Optionally, [built-in database authentication](https://cloud.google.com/sql/docs/postgres/built-in-authentication) using a username and password to access the Cloud SQL database can also be used. Just provide the optional `user` and `password` arguments to `PostgresEngine.from_instance()`:\n", - "\n", - "* `user` : Database user to use for built-in database authentication and login\n", - "* `password` : Database password to use for built-in database authentication and login.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "4576e914a866fb40", - "metadata": { - "ExecuteTime": { - "end_time": "2023-08-28T10:04:38.077748Z", - "start_time": "2023-08-28T10:04:36.105894Z" - }, - "id": "4576e914a866fb40", - "jupyter": { - "outputs_hidden": false - } - }, - "outputs": [], - "source": [ - "from langchain_google_cloud_sql_pg import PostgresEngine\n", - "\n", - "engine = PostgresEngine.from_instance(\n", - " project_id=PROJECT_ID, region=REGION, instance=INSTANCE, database=DATABASE\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "qPV8WfWr7O54", - "metadata": { - "id": "qPV8WfWr7O54" - }, - "source": [ - "### Initialize a table\n", - "The `PostgresChatMessageHistory` class requires a database table with a specific schema in order to store the chat message history.\n", - "\n", - "The `PostgresEngine` engine has a helper method `init_chat_history_table()` that can be used to create a table with the proper schema for you." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "TEu4VHArRttE", - "metadata": { - "id": "TEu4VHArRttE" - }, - "outputs": [], - "source": [ - "engine.init_chat_history_table(table_name=TABLE_NAME)" - ] - }, - { - "cell_type": "markdown", - "id": "345b76b8", - "metadata": {}, - "source": [ - "#### Optional Tip: 💡\n", - "You can also specify a schema name by passing `schema_name` wherever you pass `table_name`. Eg:\n", - "\n", - "```python\n", - "SCHEMA_NAME=\"my_schema\"\n", - "\n", - "engine.init_chat_history_table(\n", - " table_name=TABLE_NAME,\n", - " schema_name=SCHEMA_NAME # Default: \"public\"\n", - ")\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "zSYQTYf3UfOi", - "metadata": { - "id": "zSYQTYf3UfOi" - }, - "source": [ - "### PostgresChatMessageHistory\n", - "\n", - "To initialize the `PostgresChatMessageHistory` class you need to provide only 3 things:\n", - "\n", - "1. `engine` - An instance of a `PostgresEngine` engine.\n", - "1. `session_id` - A unique identifier string that specifies an id for the session.\n", - "1. `table_name` : The name of the table within the Cloud SQL database to store the chat message history.\n", - "1. `schema_name` : The name of the database schema containing the chat message history table." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "Kq7RLtfOq0wi", - "metadata": { - "id": "Kq7RLtfOq0wi" - }, - "outputs": [], - "source": [ - "from langchain_google_cloud_sql_pg import PostgresChatMessageHistory\n", - "\n", - "history = PostgresChatMessageHistory.create_sync(\n", - " engine,\n", - " session_id=\"test_session\",\n", - " table_name=TABLE_NAME,\n", - " # schema_name=SCHEMA_NAME,\n", - ")\n", - "history.add_user_message(\"hi!\")\n", - "history.add_ai_message(\"whats up?\")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "b476688cbb32ba90", - "metadata": { - "ExecuteTime": { - "end_time": "2023-08-28T10:04:38.929396Z", - "start_time": "2023-08-28T10:04:38.915727Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "b476688cbb32ba90", - "jupyter": { - "outputs_hidden": false - }, - "outputId": "a19e5cd8-4225-476a-d28d-e870c6b838bb" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[HumanMessage(content='hi!'), AIMessage(content='whats up?')]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "history.messages" - ] - }, - { - "cell_type": "markdown", - "id": "ss6CbqcTTedr", - "metadata": { - "id": "ss6CbqcTTedr" - }, - "source": [ - "#### Cleaning up\n", - "When the history of a specific session is obsolete and can be deleted, it can be done the following way.\n", - "\n", - "**Note:** Once deleted, the data is no longer stored in Cloud SQL and is gone forever." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "3khxzFxYO7x6", - "metadata": { - "id": "3khxzFxYO7x6" - }, - "outputs": [], - "source": [ - "history.clear()" - ] - }, - { - "cell_type": "markdown", - "id": "2e5337719d5614fd", - "metadata": { - "id": "2e5337719d5614fd" - }, - "source": [ - "## 🔗 Chaining\n", - "\n", - "We can easily combine this message history class with [LCEL Runnables](/docs/expression_language/how_to/message_history)\n", - "\n", - "To do this we will use one of [Google's Vertex AI chat models](https://python.langchain.com/docs/integrations/chat/google_vertex_ai_palm) which requires that you [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com) in your Google Cloud Project.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "hYtHM3-TOMCe", - "metadata": { - "id": "hYtHM3-TOMCe" - }, - "outputs": [], - "source": [ - "# enable Vertex AI API\n", - "!gcloud services enable aiplatform.googleapis.com" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "6558418b-0ece-4d01-9661-56d562d78f7a", - "metadata": { - "id": "6558418b-0ece-4d01-9661-56d562d78f7a" - }, - "outputs": [], - "source": [ - "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", - "from langchain_core.runnables.history import RunnableWithMessageHistory\n", - "from langchain_google_vertexai import ChatVertexAI" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "82149122-61d3-490d-9bdb-bb98606e8ba1", - "metadata": { - "id": "82149122-61d3-490d-9bdb-bb98606e8ba1" - }, - "outputs": [], - "source": [ - "prompt = ChatPromptTemplate.from_messages(\n", - " [\n", - " (\"system\", \"You are a helpful assistant.\"),\n", - " MessagesPlaceholder(variable_name=\"history\"),\n", - " (\"human\", \"{question}\"),\n", - " ]\n", - ")\n", - "\n", - "chain = prompt | ChatVertexAI(project=PROJECT_ID)" - ] + "cells": [ + { + "cell_type": "markdown", + "id": "f22eab3f84cbeb37", + "metadata": { + "id": "f22eab3f84cbeb37" + }, + "source": [ + "# Google Cloud SQL for PostgreSQL\n", + "\n", + "> [Cloud SQL](https://cloud.google.com/sql) is a fully managed relational database service that offers high performance, seamless integration, and impressive scalability. It offers MySQL, PostgreSQL, and SQL Server database engines. Extend your database application to build AI-powered experiences leveraging Cloud SQL's Langchain integrations.\n", + "\n", + "This notebook goes over how to use `Cloud SQL for PostgreSQL` to store chat message history with the `PostgresChatMessageHistory` class.\n", + "\n", + "Learn more about the package on [GitHub](https://github.com/googleapis/langchain-google-cloud-sql-pg-python/).\n", + "\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/googleapis/langchain-google-cloud-sql-pg-python/blob/main/docs/chat_message_history.ipynb)" + ] + }, + { + "cell_type": "markdown", + "id": "da400c79-a360-43e2-be60-401fd02b2819", + "metadata": { + "id": "da400c79-a360-43e2-be60-401fd02b2819" + }, + "source": [ + "## Before You Begin\n", + "\n", + "To run this notebook, you will need to do the following:\n", + "\n", + " * [Create a Google Cloud Project](https://developers.google.com/workspace/guides/create-project)\n", + " * [Enable the Cloud SQL Admin API.](https://console.cloud.google.com/marketplace/product/google/sqladmin.googleapis.com)\n", + " * [Create a Cloud SQL for PostgreSQL instance](https://cloud.google.com/sql/docs/postgres/create-instance)\n", + " * [Create a Cloud SQL database](https://cloud.google.com/sql/docs/mysql/create-manage-databases)\n", + " * [Add an IAM database user to the database](https://cloud.google.com/sql/docs/postgres/add-manage-iam-users#creating-a-database-user) (Optional)" + ] + }, + { + "cell_type": "markdown", + "id": "Mm7-fG_LltD7", + "metadata": { + "id": "Mm7-fG_LltD7" + }, + "source": [ + "### 🦜🔗 Library Installation\n", + "The integration lives in its own `langchain-google-cloud-sql-pg` package, so we need to install it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1VELXvcj8AId", + "metadata": { + "id": "1VELXvcj8AId" + }, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchain-google-cloud-sql-pg langchain-google-vertexai" + ] + }, + { + "cell_type": "markdown", + "id": "98TVoM3MNDHu", + "metadata": { + "id": "98TVoM3MNDHu" + }, + "source": [ + "**Colab only:** Uncomment the following cell to restart the kernel or use the button to restart the kernel. For Vertex AI Workbench you can restart the terminal using the button on top." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "v6jBDnYnNM08", + "metadata": { + "id": "v6jBDnYnNM08" + }, + "outputs": [], + "source": [ + "# # Automatically restart kernel after installs so that your environment can access the new packages\n", + "# import IPython\n", + "\n", + "# app = IPython.Application.instance()\n", + "# app.kernel.do_shutdown(True)" + ] + }, + { + "cell_type": "markdown", + "id": "yygMe6rPWxHS", + "metadata": { + "id": "yygMe6rPWxHS" + }, + "source": [ + "### 🔐 Authentication\n", + "Authenticate to Google Cloud as the IAM user logged into this notebook in order to access your Google Cloud Project.\n", + "\n", + "* If you are using Colab to run this notebook, use the cell below and continue.\n", + "* If you are using Vertex AI Workbench, check out the setup instructions [here](https://github.com/GoogleCloudPlatform/generative-ai/tree/main/setup-env)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "PTXN1_DSXj2b", + "metadata": { + "id": "PTXN1_DSXj2b" + }, + "outputs": [], + "source": [ + "from google.colab import auth\n", + "\n", + "auth.authenticate_user()" + ] + }, + { + "cell_type": "markdown", + "id": "NEvB9BoLEulY", + "metadata": { + "id": "NEvB9BoLEulY" + }, + "source": [ + "### ☁ Set Your Google Cloud Project\n", + "Set your Google Cloud project so that you can leverage Google Cloud resources within this notebook.\n", + "\n", + "If you don't know your project ID, try the following:\n", + "\n", + "* Run `gcloud config list`.\n", + "* Run `gcloud projects list`.\n", + "* See the support page: [Locate the project ID](https://support.google.com/googleapi/answer/7014113)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "gfkS3yVRE4_W", + "metadata": { + "cellView": "form", + "id": "gfkS3yVRE4_W" + }, + "outputs": [], + "source": [ + "# @markdown Please fill in the value below with your Google Cloud project ID and then run the cell.\n", + "\n", + "PROJECT_ID = \"my-project-id\" # @param {type:\"string\"}\n", + "\n", + "# Set the project id\n", + "!gcloud config set project {PROJECT_ID}" + ] + }, + { + "cell_type": "markdown", + "id": "rEWWNoNnKOgq", + "metadata": { + "id": "rEWWNoNnKOgq" + }, + "source": [ + "### 💡 API Enablement\n", + "The `langchain-google-cloud-sql-pg` package requires that you [enable the Cloud SQL Admin API](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin.googleapis.com) in your Google Cloud Project." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5utKIdq7KYi5", + "metadata": { + "id": "5utKIdq7KYi5" + }, + "outputs": [], + "source": [ + "# enable Cloud SQL Admin API\n", + "!gcloud services enable sqladmin.googleapis.com" + ] + }, + { + "cell_type": "markdown", + "id": "f8f2830ee9ca1e01", + "metadata": { + "id": "f8f2830ee9ca1e01" + }, + "source": [ + "## Basic Usage" + ] + }, + { + "cell_type": "markdown", + "id": "OMvzMWRrR6n7", + "metadata": { + "id": "OMvzMWRrR6n7" + }, + "source": [ + "### Set Cloud SQL database values\n", + "Find your database values, in the [Cloud SQL Instances page](https://console.cloud.google.com/sql?_ga=2.223735448.2062268965.1707700487-2088871159.1707257687)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "irl7eMFnSPZr", + "metadata": { + "id": "irl7eMFnSPZr" + }, + "outputs": [], + "source": [ + "# @title Set Your Values Here { display-mode: \"form\" }\n", + "REGION = \"us-central1\" # @param {type: \"string\"}\n", + "INSTANCE = \"my-postgresql-instance\" # @param {type: \"string\"}\n", + "DATABASE = \"my-database\" # @param {type: \"string\"}\n", + "TABLE_NAME = \"message_store\" # @param {type: \"string\"}" + ] + }, + { + "cell_type": "markdown", + "id": "QuQigs4UoFQ2", + "metadata": { + "id": "QuQigs4UoFQ2" + }, + "source": [ + "### PostgresEngine Connection Pool\n", + "\n", + "One of the requirements and arguments to establish Cloud SQL as a ChatMessageHistory memory store is a `PostgresEngine` object. The `PostgresEngine` configures a connection pool to your Cloud SQL database, enabling successful connections from your application and following industry best practices.\n", + "\n", + "To create a `PostgresEngine` using `PostgresEngine.from_instance()` you need to provide only 4 things:\n", + "\n", + "1. `project_id` : Project ID of the Google Cloud Project where the Cloud SQL instance is located.\n", + "1. `region` : Region where the Cloud SQL instance is located.\n", + "1. `instance` : The name of the Cloud SQL instance.\n", + "1. `database` : The name of the database to connect to on the Cloud SQL instance.\n", + "\n", + "By default, [IAM database authentication](https://cloud.google.com/sql/docs/postgres/iam-authentication#iam-db-auth) will be used as the method of database authentication. This library uses the IAM principal belonging to the [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/application-default-credentials) sourced from the envionment.\n", + "\n", + "For more informatin on IAM database authentication please see:\n", + "* [Configure an instance for IAM database authentication](https://cloud.google.com/sql/docs/postgres/create-edit-iam-instances)\n", + "* [Manage users with IAM database authentication](https://cloud.google.com/sql/docs/postgres/add-manage-iam-users)\n", + "\n", + "Optionally, [built-in database authentication](https://cloud.google.com/sql/docs/postgres/built-in-authentication) using a username and password to access the Cloud SQL database can also be used. Just provide the optional `user` and `password` arguments to `PostgresEngine.from_instance()`:\n", + "\n", + "* `user` : Database user to use for built-in database authentication and login\n", + "* `password` : Database password to use for built-in database authentication and login.\n", + "\n", + "To connect to your Cloud SQL instance from this notebook, you will need to enable public IP on your instance. Alternatively, you can follow [these instructions](https://cloud.google.com/sql/docs/postgres/connect-to-instance-from-outside-vpc) to connect to an Cloud SQL for PostgreSQL instance with Private IP from outside your VPC. Learn more about [specifying IP types](https://github.com/GoogleCloudPlatform/cloud-sql-python-connector?tab=readme-ov-file#specifying-ip-address-type).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4576e914a866fb40", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-28T10:04:38.077748Z", + "start_time": "2023-08-28T10:04:36.105894Z" + }, + "id": "4576e914a866fb40", + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "from langchain_google_cloud_sql_pg import PostgresEngine\n", + "\n", + "engine = PostgresEngine.from_instance(\n", + " project_id=PROJECT_ID,\n", + " region=REGION,\n", + " instance=INSTANCE,\n", + " database=DATABASE,\n", + " ip_type=\"public\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "qPV8WfWr7O54", + "metadata": { + "id": "qPV8WfWr7O54" + }, + "source": [ + "### Initialize a table\n", + "The `PostgresChatMessageHistory` class requires a database table with a specific schema in order to store the chat message history.\n", + "\n", + "The `PostgresEngine` engine has a helper method `init_chat_history_table()` that can be used to create a table with the proper schema for you." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "TEu4VHArRttE", + "metadata": { + "id": "TEu4VHArRttE" + }, + "outputs": [], + "source": [ + "engine.init_chat_history_table(table_name=TABLE_NAME)" + ] + }, + { + "cell_type": "markdown", + "id": "345b76b8", + "metadata": {}, + "source": [ + "#### Optional Tip: 💡\n", + "You can also specify a schema name by passing `schema_name` wherever you pass `table_name`. Eg:\n", + "\n", + "```python\n", + "SCHEMA_NAME=\"my_schema\"\n", + "\n", + "engine.init_chat_history_table(\n", + " table_name=TABLE_NAME,\n", + " schema_name=SCHEMA_NAME # Default: \"public\"\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "zSYQTYf3UfOi", + "metadata": { + "id": "zSYQTYf3UfOi" + }, + "source": [ + "### PostgresChatMessageHistory\n", + "\n", + "To initialize the `PostgresChatMessageHistory` class you need to provide only 3 things:\n", + "\n", + "1. `engine` - An instance of a `PostgresEngine` engine.\n", + "1. `session_id` - A unique identifier string that specifies an id for the session.\n", + "1. `table_name` : The name of the table within the Cloud SQL database to store the chat message history.\n", + "1. `schema_name` : The name of the database schema containing the chat message history table." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "Kq7RLtfOq0wi", + "metadata": { + "id": "Kq7RLtfOq0wi" + }, + "outputs": [], + "source": [ + "from langchain_google_cloud_sql_pg import PostgresChatMessageHistory\n", + "\n", + "history = PostgresChatMessageHistory.create_sync(\n", + " engine,\n", + " session_id=\"test_session\",\n", + " table_name=TABLE_NAME,\n", + " # schema_name=SCHEMA_NAME,\n", + ")\n", + "history.add_user_message(\"hi!\")\n", + "history.add_ai_message(\"whats up?\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b476688cbb32ba90", + "metadata": { + "ExecuteTime": { + "end_time": "2023-08-28T10:04:38.929396Z", + "start_time": "2023-08-28T10:04:38.915727Z" }, - { - "cell_type": "code", - "execution_count": 16, - "id": "2df90853-b67c-490f-b7f8-b69d69270b9c", - "metadata": { - "id": "2df90853-b67c-490f-b7f8-b69d69270b9c" - }, - "outputs": [], - "source": [ - "chain_with_history = RunnableWithMessageHistory(\n", - " chain,\n", - " lambda session_id: PostgresChatMessageHistory.create_sync(\n", - " engine,\n", - " session_id=session_id,\n", - " table_name=TABLE_NAME,\n", - " # schema_name=SCHEMA_NAME,\n", - " ),\n", - " input_messages_key=\"question\",\n", - " history_messages_key=\"history\",\n", - ")" - ] + "colab": { + "base_uri": "https://localhost:8080/" }, - { - "cell_type": "code", - "execution_count": 17, - "id": "0ce596b8-3b78-48fd-9f92-46dccbbfd58b", - "metadata": { - "id": "0ce596b8-3b78-48fd-9f92-46dccbbfd58b" - }, - "outputs": [], - "source": [ - "# This is where we configure the session id\n", - "config = {\"configurable\": {\"session_id\": \"test_session\"}}" - ] + "id": "b476688cbb32ba90", + "jupyter": { + "outputs_hidden": false }, + "outputId": "a19e5cd8-4225-476a-d28d-e870c6b838bb" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 18, - "id": "38e1423b-ba86-4496-9151-25932fab1a8b", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "38e1423b-ba86-4496-9151-25932fab1a8b", - "outputId": "d5c93570-4b0b-4fe8-d19c-4b361fe74291" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "AIMessage(content=' Hello Bob, how can I help you today?')" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chain_with_history.invoke({\"question\": \"Hi! I'm bob\"}, config=config)" + "data": { + "text/plain": [ + "[HumanMessage(content='hi!'), AIMessage(content='whats up?')]" ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "history.messages" + ] + }, + { + "cell_type": "markdown", + "id": "ss6CbqcTTedr", + "metadata": { + "id": "ss6CbqcTTedr" + }, + "source": [ + "#### Cleaning up\n", + "When the history of a specific session is obsolete and can be deleted, it can be done the following way.\n", + "\n", + "**Note:** Once deleted, the data is no longer stored in Cloud SQL and is gone forever." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3khxzFxYO7x6", + "metadata": { + "id": "3khxzFxYO7x6" + }, + "outputs": [], + "source": [ + "history.clear()" + ] + }, + { + "cell_type": "markdown", + "id": "2e5337719d5614fd", + "metadata": { + "id": "2e5337719d5614fd" + }, + "source": [ + "## 🔗 Chaining\n", + "\n", + "We can easily combine this message history class with [LCEL Runnables](/docs/expression_language/how_to/message_history)\n", + "\n", + "To do this we will use one of [Google's Vertex AI chat models](https://python.langchain.com/docs/integrations/chat/google_vertex_ai_palm) which requires that you [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com) in your Google Cloud Project.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "hYtHM3-TOMCe", + "metadata": { + "id": "hYtHM3-TOMCe" + }, + "outputs": [], + "source": [ + "# enable Vertex AI API\n", + "!gcloud services enable aiplatform.googleapis.com" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "6558418b-0ece-4d01-9661-56d562d78f7a", + "metadata": { + "id": "6558418b-0ece-4d01-9661-56d562d78f7a" + }, + "outputs": [], + "source": [ + "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", + "from langchain_core.runnables.history import RunnableWithMessageHistory\n", + "from langchain_google_vertexai import ChatVertexAI" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "82149122-61d3-490d-9bdb-bb98606e8ba1", + "metadata": { + "id": "82149122-61d3-490d-9bdb-bb98606e8ba1" + }, + "outputs": [], + "source": [ + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\"system\", \"You are a helpful assistant.\"),\n", + " MessagesPlaceholder(variable_name=\"history\"),\n", + " (\"human\", \"{question}\"),\n", + " ]\n", + ")\n", + "\n", + "chain = prompt | ChatVertexAI(project=PROJECT_ID)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "2df90853-b67c-490f-b7f8-b69d69270b9c", + "metadata": { + "id": "2df90853-b67c-490f-b7f8-b69d69270b9c" + }, + "outputs": [], + "source": [ + "chain_with_history = RunnableWithMessageHistory(\n", + " chain,\n", + " lambda session_id: PostgresChatMessageHistory.create_sync(\n", + " engine,\n", + " session_id=session_id,\n", + " table_name=TABLE_NAME,\n", + " # schema_name=SCHEMA_NAME,\n", + " ),\n", + " input_messages_key=\"question\",\n", + " history_messages_key=\"history\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0ce596b8-3b78-48fd-9f92-46dccbbfd58b", + "metadata": { + "id": "0ce596b8-3b78-48fd-9f92-46dccbbfd58b" + }, + "outputs": [], + "source": [ + "# This is where we configure the session id\n", + "config = {\"configurable\": {\"session_id\": \"test_session\"}}" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "38e1423b-ba86-4496-9151-25932fab1a8b", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "38e1423b-ba86-4496-9151-25932fab1a8b", + "outputId": "d5c93570-4b0b-4fe8-d19c-4b361fe74291" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 19, - "id": "2ee4ee62-a216-4fb1-bf33-57476a84cf16", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "2ee4ee62-a216-4fb1-bf33-57476a84cf16", - "outputId": "288fe388-3f60-41b8-8edb-37cfbec18981" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "AIMessage(content=' Your name is Bob.')" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chain_with_history.invoke({\"question\": \"Whats my name\"}, config=config)" + "data": { + "text/plain": [ + "AIMessage(content=' Hello Bob, how can I help you today?')" ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { + ], + "source": [ + "chain_with_history.invoke({\"question\": \"Hi! I'm bob\"}, config=config)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "2ee4ee62-a216-4fb1-bf33-57476a84cf16", + "metadata": { "colab": { - "provenance": [], - "toc_visible": true + "base_uri": "https://localhost:8080/" }, - "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.8.8" + "id": "2ee4ee62-a216-4fb1-bf33-57476a84cf16", + "outputId": "288fe388-3f60-41b8-8edb-37cfbec18981" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "AIMessage(content=' Your name is Bob.')" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" } + ], + "source": [ + "chain_with_history.invoke({\"question\": \"Whats my name\"}, config=config)" + ] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file + "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.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/document_loader.ipynb b/docs/document_loader.ipynb index c0b59a09..c98482d3 100644 --- a/docs/document_loader.ipynb +++ b/docs/document_loader.ipynb @@ -203,7 +203,10 @@ "Optionally, [built-in database authentication](https://cloud.google.com/sql/docs/postgres/users) using a username and password to access the Cloud SQL database can also be used. Just provide the optional `user` and `password` arguments to `PostgresEngine.from_instance()`:\n", "\n", "* `user` : Database user to use for built-in database authentication and login\n", - "* `password` : Database password to use for built-in database authentication and login.\n" + "* `password` : Database password to use for built-in database authentication and login.\n", + "\n", + "\n", + "To connect to your Cloud SQL instance from this notebook, you will need to enable public IP on your instance. Alternatively, you can follow [these instructions](https://cloud.google.com/sql/docs/postgres/connect-to-instance-from-outside-vpc) to connect to an Cloud SQL for PostgreSQL instance with Private IP from outside your VPC. Learn more about [specifying IP types](https://github.com/GoogleCloudPlatform/cloud-sql-python-connector?tab=readme-ov-file#specifying-ip-address-type)." ] }, { @@ -226,6 +229,7 @@ " region=REGION,\n", " instance=INSTANCE,\n", " database=DATABASE,\n", + " ip_type=\"public\",\n", ")" ] }, diff --git a/docs/vector_store.ipynb b/docs/vector_store.ipynb index 4071dbdf..cf2814fe 100644 --- a/docs/vector_store.ipynb +++ b/docs/vector_store.ipynb @@ -209,7 +209,9 @@ "Optionally, [built-in database authentication](https://cloud.google.com/sql/docs/postgres/built-in-authentication) using a username and password to access the Cloud SQL database can also be used. Just provide the optional `user` and `password` arguments to `PostgresEngine.from_instance()`:\n", "\n", "* `user` : Database user to use for built-in database authentication and login\n", - "* `password` : Database password to use for built-in database authentication and login.\n" + "* `password` : Database password to use for built-in database authentication and login.\n", + "\n", + "To connect to your Cloud SQL instance from this notebook, you will need to enable public IP on your instance. Alternatively, you can follow [these instructions](https://cloud.google.com/sql/docs/postgres/connect-to-instance-from-outside-vpc) to connect to an Cloud SQL for PostgreSQL instance with Private IP from outside your VPC. Learn more about [specifying IP types](https://github.com/GoogleCloudPlatform/cloud-sql-python-connector?tab=readme-ov-file#specifying-ip-address-type).\n" ] }, { @@ -228,7 +230,11 @@ "from langchain_google_cloud_sql_pg import PostgresEngine\n", "\n", "engine = await PostgresEngine.afrom_instance(\n", - " project_id=PROJECT_ID, region=REGION, instance=INSTANCE, database=DATABASE\n", + " project_id=PROJECT_ID,\n", + " region=REGION,\n", + " instance=INSTANCE,\n", + " database=DATABASE,\n", + " ip_type=\"public\",\n", ")" ] }, diff --git a/samples/langchain_quick_start.ipynb b/samples/langchain_quick_start.ipynb index c6361566..ff2c5828 100644 --- a/samples/langchain_quick_start.ipynb +++ b/samples/langchain_quick_start.ipynb @@ -1,1019 +1,1022 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "6zvUr-Qev6lL" - }, - "outputs": [], - "source": [ - "# Copyright 2024 Google LLC\n", - "#\n", - "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", - "# you may not use this file except in compliance with the License.\n", - "# You may obtain a copy of the License at\n", - "#\n", - "# https://www.apache.org/licenses/LICENSE-2.0\n", - "#\n", - "# Unless required by applicable law or agreed to in writing, software\n", - "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", - "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", - "# See the License for the specific language governing permissions and\n", - "# limitations under the License." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ob11AkrStrRI" - }, - "source": [ - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/googleapis/langchain-google-cloud-sql-pg-python/blob/main/samples/langchain_quick_start.ipynb)\n", - "\n", - "---\n", - "# **Introduction**\n", - "\n", - "In this codelab, you'll learn how to create a powerful interactive generative AI application using Retrieval Augmented Generation powered by [Cloud SQL for PostgreSQL](https://cloud.google.com/sql/docs/postgres) and [LangChain](https://www.langchain.com/). We will be creating an application grounded in a [Netflix Movie dataset](https://www.kaggle.com/datasets/shivamb/netflix-shows), allowing you to interact with movie data in exciting new ways." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ma6pEng3ypbA" - }, - "source": [ - "## Prerequisites\n", - "\n", - "* A basic understanding of the Google Cloud Console\n", - "* Basic skills in command line interface and Google Cloud shell\n", - "* Basic python knowledge" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "DzDgqJHgysy1" - }, - "source": [ - "## What you'll learn\n", - "\n", - "* How to deploy a Cloud SQL for PostgreSQL instance\n", - "* How to use Cloud SQL for PostgreSQL as a DocumentLoader\n", - "* How to use Cloud SQL for PostgreSQL as a VectorStore\n", - "* How to use Cloud SQL for PostgreSQL for ChatMessageHistory storage" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FbcZUjT1yvTq" - }, - "source": [ - "## What you'll need\n", - "* A Google Cloud Account and Google Cloud Project\n", - "* A web browser such as [Chrome](https://www.google.com/chrome/)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vHdR4fF3vLWA" - }, - "source": [ - "# **Setup and Requirements**\n", - "\n", - "In the following instructions you will learn to:\n", - "1. Install required dependencies for our application\n", - "2. Set up authentication for our project\n", - "3. Set up a Cloud SQL for PostgreSQL Instance\n", - "4. Import the data used by our application" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "uy9KqgPQ4GBi" - }, - "source": [ - "## Install dependencies\n", - "First you will need to install the dependencies needed to run this demo app." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "M_ppDxYf4Gqs" - }, - "outputs": [], - "source": [ - "%pip install --upgrade --quiet langchain-google-cloud-sql-pg langchain-google-vertexai langchain" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Colab only:** Uncomment the following cell to restart the kernel or use the button to restart the kernel. For Vertex AI Workbench you can restart the terminal using the button on top." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Automatically restart kernel after installs so that your environment can access the new packages\n", - "import IPython\n", - "\n", - "app = IPython.Application.instance()\n", - "app.kernel.do_shutdown(True)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "DeUbHclxw7_l" - }, - "source": [ - "## Authenticate to Google Cloud within Colab\n", - "In order to access your Google Cloud Project from this notebook, you will need to Authenticate as an IAM user." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "a168rJE1xDHO" - }, - "outputs": [], - "source": [ - "from google.colab import auth\n", - "\n", - "auth.authenticate_user()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "UCiNGP1Qxd6x" - }, - "source": [ - "## Connect Your Google Cloud Project\n", - "Time to connect your Google Cloud Project to this notebook so that you can leverage Google Cloud from within Colab." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "cellView": "form", - "id": "qjFuhRhVxlWP" - }, - "outputs": [], - "source": [ - "# @markdown Please fill in the value below with your GCP project ID and then run the cell.\n", - "\n", - "# Please fill in these values.\n", - "project_id = \"\" # @param {type:\"string\"}\n", - "\n", - "# Quick input validations.\n", - "assert project_id, \"⚠️ Please provide a Google Cloud project ID\"\n", - "\n", - "# Configure gcloud.\n", - "!gcloud config set project {project_id}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "O-oqMC5Ox-ZM" - }, - "source": [ - "## Configure Your Google Cloud Project\n", - "\n", - "Configure the following in your Google Cloud Project." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. IAM principal (user, service account, etc.) with the [Cloud SQL Client][client-role] role. The user logged into this notebook will be used as the IAM principal and will be granted the Cloud SQL Client role.\n", - "\n", - "[client-role]: https://cloud.google.com/sql/docs/mysql/roles-and-permissions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "current_user = !gcloud auth list --filter=status:ACTIVE --format=\"value(account)\"\n", - "!gcloud projects add-iam-policy-binding {project_id} \\\n", - " --member=user:{current_user[0]} \\\n", - " --role=\"roles/cloudsql.client\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "2. Enable the APIs for Cloud SQL and Vertex AI within your project." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "CKWrwyfzyTwH" - }, - "outputs": [], - "source": [ - "# Enable GCP services\n", - "!gcloud services enable sqladmin.googleapis.com aiplatform.googleapis.com" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Gn8g7-wCyZU6" - }, - "source": [ - "## Set up Cloud SQL\n", - "You will need a **Postgres** Cloud SQL instance for the following stages of this notebook." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "T616pEOUygYQ" - }, - "source": [ - "### Create a Postgres Instance\n", - "Running the below cell will verify the existence of the Cloud SQL instance and or create a new instance and database if one does not exist.\n", - "\n", - "> ⏳ - Creating a Cloud SQL instance may take a few minutes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "cellView": "form", - "id": "XXI1uUu3y8gc" - }, - "outputs": [], - "source": [ - "#@markdown Please fill in the both the Google Cloud region and name of your Cloud SQL instance. Once filled in, run the cell.\n", - "\n", - "# Please fill in these values.\n", - "region = \"us-central1\" #@param {type:\"string\"}\n", - "instance_name = \"langchain-quickstart-instance\" #@param {type:\"string\"}\n", - "database_name = \"langchain-quickstart-db\" #@param {type:\"string\"}\n", - "password = input(\"Please provide a password to be used for 'postgres' database user: \")\n", - "\n", - "# Quick input validations.\n", - "assert region, \"⚠️ Please provide a Google Cloud region\"\n", - "assert instance_name, \"⚠️ Please provide the name of your instance\"\n", - "assert database_name, \"⚠️ Please provide the name of your database_name\"\n", - "\n", - "# check if Cloud SQL instance exists in the provided region\n", - "database_version = !gcloud sql instances describe {instance_name} --format=\"value(databaseVersion)\"\n", - "if database_version[0].startswith(\"POSTGRES\"):\n", - " print(\"Found existing Postgres Cloud SQL Instance!\")\n", - "else:\n", - " print(\"Creating new Cloud SQL instance...\")\n", - " !gcloud sql instances create {instance_name} --database-version=POSTGRES_15 \\\n", - " --region={region} --cpu=1 --memory=4GB --root-password={password} \\\n", - " --database-flags=cloudsql.iam_authentication=On\n", - " !gcloud sql databases create {database_name} --instance={instance_name}\n", - "\n", - "\n", - "databases = !gcloud sql databases list --instance={instance_name} --format=\"value(name)\"\n", - "if database_name not in databases:\n", - " !gcloud sql databases create {database_name} --instance={instance_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HdolCWyatZmG" - }, - "source": [ - "## Import data to your database\n", - "\n", - "Now that you have your database, you will need to import data! We will be using a [Netflix Dataset from Kaggle](https://www.kaggle.com/datasets/shivamb/netflix-shows). Here is what the data looks like:" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "36-FBKzJ-tLa" - }, - "source": [ - "| show_id | type | title | director | cast | country | date_added | release_year | rating | duration | listed_in | description |\n", - "|---------|---------|----------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-------------------|--------------|--------|-----------|----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n", - "| s1 | Movie | Dick Johnson Is Dead | Kirsten Johnson | | United States | September 25, 2021 | 2020 | PG-13 | 90 min | Documentaries | As her father nears the end of his life, filmmaker Kirsten Johnson stages his death in inventive and comical ways to help them both face the inevitable. |\n", - "| s2 | TV Show | Blood & Water | | Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile Tshabalala, Getmore Sithole, Cindy Mahlangu, Ryle De Morny, Greteli Fincham, Sello Maake Ka-Ncube, Odwa Gwanya, Mekaila Mathys, Sandi Schultz, Duane Williams, Shamilla Miller, Patrick Mofokeng | South Africa | September 24, 2021 | 2021 | TV-MA | 2 Seasons | International TV Shows, TV Dramas, TV Mysteries | After crossing paths at a party, a Cape Town teen sets out to prove whether a private-school swimming star is her sister who was abducted at birth. |\n", - "| s3 | TV Show | Ganglands | Julien Leclercq | Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, Geert Van Rampelberg, Bakary Diombera | | September 24, 2021 | 2021 | TV-MA | 1 Season | Crime TV Shows, International TV Shows, TV Action & Adventure | To protect his family from a powerful drug lord, skilled thief Mehdi and his expert team of robbers are pulled into a violent and deadly turf war. |\n", - "| s4 | TV Show | Jailbirds New Orleans | | | | September 24, 2021 | 2021 | TV-MA | 1 Season | Docuseries, Reality TV | Feuds, flirtations and toilet talk go down among the incarcerated women at the Orleans Justice Center in New Orleans on this gritty reality series. |\n", - "| s5 | TV Show | Kota Factory | | Mayur More, Jitendra Kumar, Ranjan Raj, Alam Khan, Ahsaas Channa, Revathi Pillai, Urvi Singh, Arun Kumar | India | September 24, 2021 | 2021 | TV-MA | 2 Seasons | International TV Shows, Romantic TV Shows, TV Comedies | In a city of coaching centers known to train India’s finest collegiate minds, an earnest but unexceptional student and his friends navigate campus life. |\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "kQ2KWsYI_Msa" - }, - "source": [ - "You won't need to directly load the csv data into your database. Instead we prepared a table, \"netflix_titles\", in the format of a `.sql` file for Postgres. You can easily import the table into your database with one `gcloud` command." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qbLhv9jgD8nm" - }, - "outputs": [], - "source": [ - "# Import the Netflix titles table using gcloud command\n", - "import_command_output = !gcloud sql import sql {instance_name} gs://cloud-samples-data/langchain/cloud-sql/postgres/first_five_netflix_titles.sql --database={database_name} --quiet\n", - "\n", - "if \"Imported data\" in str(import_command_output):\n", - " print(import_command_output)\n", - "elif \"already exists\" in str(import_command_output):\n", - " print(\"Did not import because the table already existed.\")\n", - "else:\n", - " raise Exception(f\"The import seems failed:\\n{import_command_output}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "SsGS80H04bDN" - }, - "source": [ - "# **Use case 1: Cloud SQL for PostgreSQL as a document loader**\n", - "\n", - "Now that you have data in your database, you are ready to use Cloud SQL for PostgreSQL as a [document loader](https://python.langchain.com/docs/modules/data_connection/document_loaders/). This means we will pull data from the database and load it into memory as documents. We can then feed these documents into the vector store." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "-CQgPON8dwSK" - }, - "source": [ - "Next let's connect to our CloudSQL PostgreSQL instance using the PostgresEngine class." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "id": "zrwTsWHMkQ_v" - }, - "outputs": [], - "source": [ - "from langchain_google_cloud_sql_pg import PostgresLoader, PostgresEngine, Column\n", - "\n", - "pg_engine = PostgresEngine.from_instance(\n", - " project_id=project_id,\n", - " instance=instance_name,\n", - " region=region,\n", - " database=database_name,\n", - " user=\"postgres\",\n", - " password=password,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "8s-C0P-Oee69" - }, - "source": [ - "Once we initialize a PostgresEngine object, we can pass it into the PostgresLoader to connect to a specific database. As you can see we also pass in a query, table_name and a list of columns. The query tells the loader what query to use to pull data. The \"content_columns\" argument refers to the columns that will be used as \"content\" in the document object we will later construct. The rest of the columns in that table will become the \"metadata\" associated with the documents." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "id": "2SdFJT6Vece1" - }, - "outputs": [], - "source": [ - "table_name = \"netflix_titles\"\n", - "content_columns = [\"title\", \"director\", \"cast\", \"description\"]\n", - "loader = await PostgresLoader.create(\n", - " engine=pg_engine,\n", - " query=f\"SELECT * FROM {table_name};\",\n", - " content_columns=content_columns,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "dsL-KFrmfuS1" - }, - "source": [ - "Then let's run the function to pull our documents from out database using our document loader. You can see the first 5 documents from the database here. Nice, you just used CloudSQL for PostgreSQL as a document loader!" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "t4zTx-HLfwmW", - "outputId": "da7239e4-710d-43ce-c004-520a0af9c79f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Loaded 8802 from the database. 5 Examples:\n", - "page_content='Midnight Mass Mike Flanagan Kate Siegel, Zach Gilford, Hamish Linklater, Henry Thomas, Kristin Lehman, Samantha Sloyan, Igby Rigney, Rahul Kohli, Annarah Cymone, Annabeth Gish, Alex Essoe, Rahul Abburi, Matt Biedel, Michael Trucco, Crystal Balint, Louis Oliver The arrival of a charismatic young priest brings glorious miracles, ominous mysteries and renewed religious fervor to a dying town desperate to believe.' metadata={'show_id': 's6', 'type': 'TV Show', 'country': None, 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'TV-MA', 'duration': '1 Season', 'listed_in': 'TV Dramas, TV Horror, TV Mysteries'}\n", - "page_content=\"My Little Pony: A New Generation Robert Cullen, José Luis Ucha Vanessa Hudgens, Kimiko Glenn, James Marsden, Sofia Carson, Liza Koshy, Ken Jeong, Elizabeth Perkins, Jane Krakowski, Michael McKean, Phil LaMarr Equestria's divided. But a bright-eyed hero believes Earth Ponies, Pegasi and Unicorns should be pals — and, hoof to heart, she’s determined to prove it.\" metadata={'show_id': 's7', 'type': 'Movie', 'country': None, 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'PG', 'duration': '91 min', 'listed_in': 'Children & Family Movies'}\n", - "page_content='Sankofa Haile Gerima Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri On a photo shoot in Ghana, an American model slips back in time, becomes enslaved on a plantation and bears witness to the agony of her ancestral past.' metadata={'show_id': 's8', 'type': 'Movie', 'country': 'United States, Ghana, Burkina Faso, United Kingdom, Germany, Ethiopia', 'date_added': 'September 24, 2021', 'release_year': 1993, 'rating': 'TV-MA', 'duration': '125 min', 'listed_in': 'Dramas, Independent Movies, International Movies'}\n", - "page_content=\"The Great British Baking Show Andy Devonshire Mel Giedroyc, Sue Perkins, Mary Berry, Paul Hollywood A talented batch of amateur bakers face off in a 10-week competition, whipping up their best dishes in the hopes of being named the U.K.'s best.\" metadata={'show_id': 's9', 'type': 'TV Show', 'country': 'United Kingdom', 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'TV-14', 'duration': '9 Seasons', 'listed_in': 'British TV Shows, Reality TV'}\n", - "page_content=\"The Starling Theodore Melfi Melissa McCarthy, Chris O'Dowd, Kevin Kline, Timothy Olyphant, Daveed Diggs, Skyler Gisondo, Laura Harrier, Rosalind Chao, Kimberly Quinn, Loretta Devine, Ravi Kapoor A woman adjusting to life after a loss contends with a feisty bird that's taken over her garden — and a husband who's struggling to find a way forward.\" metadata={'show_id': 's10', 'type': 'Movie', 'country': 'United States', 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'PG-13', 'duration': '104 min', 'listed_in': 'Comedies, Dramas'}\n" - ] - } - ], - "source": [ - "documents = await loader.aload()\n", - "print(f\"Loaded {len(documents)} from the database. 5 Examples:\")\n", - "for doc in documents[:5]:\n", - " print(doc)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "z9uLV3bs4noo" - }, - "source": [ - "# **Use case 2: Cloud SQL for PostgreSQL as Vector Store**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "duVsSeMcgEWl" - }, - "source": [ - "Now, let's learn how to put all of the documents we just loaded into a [vector store](https://python.langchain.com/docs/modules/data_connection/vectorstores/) so that we can use vector search to answer our user's questions!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "jfH8oQJ945Ko" - }, - "source": [ - "### Create Your Vector Store table\n", - "\n", - "Based on the documents that we loaded before, we want to create a table with a vector column as our vector store. We will start it by intializing a vector table by calling the `init_vectorstore_table` function from our `engine`. As you can see we list all of the columns for our metadata. We also specify a vector size, 768, that corresponds with the length of the vectors computed by the model our embeddings service uses, Vertex AI's textembedding-gecko.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "id": "e_rmjywG47pv" - }, - "outputs": [], - "source": [ - "from langchain_google_cloud_sql_pg import PostgresEngine, Column\n", - "\n", - "sample_vector_table_name = \"movie_vector_table_samples\"\n", - "\n", - "pg_engine = PostgresEngine.from_instance(\n", - " project_id=project_id,\n", - " instance=instance_name,\n", - " region=region,\n", - " database=database_name,\n", - " user=\"postgres\",\n", - " password=password,\n", - ")\n", - "\n", - "pg_engine.init_vectorstore_table(\n", - " sample_vector_table_name,\n", - " vector_size=768,\n", - " metadata_columns=[\n", - " Column(\"show_id\", \"VARCHAR\", nullable=True),\n", - " Column(\"type\", \"VARCHAR\", nullable=True),\n", - " Column(\"country\", \"VARCHAR\", nullable=True),\n", - " Column(\"date_added\", \"VARCHAR\", nullable=True),\n", - " Column(\"release_year\", \"INTEGER\", nullable=True),\n", - " Column(\"rating\", \"VARCHAR\", nullable=True),\n", - " Column(\"duration\", \"VARCHAR\", nullable=True),\n", - " Column(\"listed_in\", \"VARCHAR\", nullable=True),\n", - " ],\n", - " overwrite_existing=True, # Enabling this will recreate the table if exists.\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "KG6rwEuJLNIo" - }, - "source": [ - "### Try inserting the documents into the vector table\n", - "\n", - "Now we will create a vector_store object backed by our vector table in the Cloud SQL database. Let's load the data from the documents to the vector table. Note that for each row, the embedding service will be called to compute the embeddings to store in the vector table. Pricing details can be found [here](https://cloud.google.com/vertex-ai/pricing)." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "id": "Wo4-7EYCIFF9" - }, - "outputs": [], - "source": [ - "from langchain_google_vertexai import VertexAIEmbeddings\n", - "from langchain_google_cloud_sql_pg import PostgresVectorStore\n", - "\n", - "# Initialize the embedding service. In this case we are using version 003 of Vertex AI's textembedding-gecko model. In general, it is good practice to specify the model version used.\n", - "embeddings_service = VertexAIEmbeddings(\n", - " model_name=\"textembedding-gecko@003\", project=project_id\n", - ")\n", - "\n", - "vector_store = PostgresVectorStore.create_sync(\n", - " engine=pg_engine,\n", - " embedding_service=embeddings_service,\n", - " table_name=sample_vector_table_name,\n", - " metadata_columns=[\n", - " \"show_id\",\n", - " \"type\",\n", - " \"country\",\n", - " \"date_added\",\n", - " \"release_year\",\n", - " \"duration\",\n", - " \"listed_in\",\n", - " ],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "fr1rP6KQ-8ag" - }, - "source": [ - "Now let's try to put the documents data into the vector table. Here is a code example to load the first 5 documents in the list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "CTks8Cy--93B" - }, - "outputs": [], - "source": [ - "import uuid\n", - "\n", - "docs_to_load = documents[:5]\n", - "\n", - "# ! Uncomment the following line to load all 8,800+ documents to the database vector table with calling the embedding service.\n", - "# docs_to_load = documents\n", - "\n", - "ids = [str(uuid.uuid4()) for i in range(len(docs_to_load))]\n", - "vector_store.add_documents(docs_to_load, ids)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "29iztdvfL2BN" - }, - "source": [ - "### Import the rest of your data into your vector table\n", - "\n", - "You don't have to call the embedding service 8,800 times to load all the documents for the demo. Instead, we have prepared a table with the all 8,800+ rows with pre-computed embeddings in a `.sql` file. Again, let's import to our DB using `gcloud` command.\n", - "\n", - "It will restore the `.sql` file to a table with vectors called `movie_vector_table`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "FEe9El7QMjHi" - }, - "outputs": [], - "source": [ - "# Import the netflix titles with vector table using gcloud command\n", - "import_command_output = !gcloud sql import sql {instance_name} gs://cloud-samples-data/langchain/cloud-sql/postgres/netflix_titles_vector_table.sql --database={database_name} --quiet\n", - "\n", - "if \"Imported data\" in str(import_command_output):\n", - " print(import_command_output)\n", - "elif \"already exists\" in str(import_command_output):\n", - " print(\"Did not import because the table already existed.\")\n", - "else:\n", - " raise Exception(f\"The import seems failed:\\n{import_command_output}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZM_OFzZrQEPs" - }, - "source": [ - "# **Use case 3: Cloud SQL for PostgreSQL as Chat Memory**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "dxqIPQtjDquk" - }, - "source": [ - "Next we will add chat history (called [“memory” in the context of LangChain](https://python.langchain.com/docs/modules/memory/)) to our application so the LLM can retain context and information across multiple interactions, leading to more coherent and sophisticated conversations or text generation. We can use Cloud SQL for PostgreSQL as “memory” storage in our application so that the LLM can use context from prior conversations to better answer the user’s prompts. First let's initialize Cloud SQL for PostgreSQL as memory storage." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "id": "vyYQILyoEAqg" - }, - "outputs": [], - "source": [ - "from langchain_google_cloud_sql_pg import PostgresChatMessageHistory, PostgresEngine\n", - "\n", - "message_table_name = \"message_store\"\n", - "\n", - "pg_engine.init_chat_history_table(table_name=message_table_name)\n", - "\n", - "chat_history = PostgresChatMessageHistory.create_sync(\n", - " pg_engine,\n", - " session_id=\"my-test-session\",\n", - " table_name=message_table_name,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "2yuXYLTCl2K1" - }, - "source": [ - "Here is an example of how you would add a user message and how you would add an ai message." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "qDVoTWZal0ZF", - "outputId": "aeb8c338-9f0d-4143-c09d-9c49478940e0" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[HumanMessage(content='What movie was Brad Pitt in?'),\n", - " AIMessage(content='Brad Pitt was in Inglourious Basterds, By the Sea, Killing Them Softly and Babel according to the given data.'),\n", - " HumanMessage(content='How about Jonny Depp?'),\n", - " AIMessage(content=\"Jonny Depp was in Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, and What's Eating Gilbert Grape according to the given data.\"),\n", - " HumanMessage(content='Are there movies about animals?'),\n", - " AIMessage(content='Yes, Rango features animals.'),\n", - " HumanMessage(content='Hi!'),\n", - " AIMessage(content=\"Hello there. I'm a model and am happy to help!\")]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chat_history.add_user_message(\"Hi!\")\n", - "chat_history.add_ai_message(\"Hello there. I'm a model and am happy to help!\")\n", - "\n", - "chat_history.messages" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "k0O9mta8RQ0v" - }, - "source": [ - "# **Conversational RAG Chain backed by Cloud SQL Postgres**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "j2OxF3JoNA7J" - }, - "source": [ - "So far we've tested with using Cloud SQL for PostgreSQL as document loader, Vector Store and Chat Memory. Now let's use it in the `ConversationalRetrievalChain`.\n", - "\n", - "We will build a chat bot that can answer movie related questions based on the vector search results.\n", - "\n", - "First let's initialize all of our PostgresSQLEngine object to use as a connection in our vector store and chat_history." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "id": "9ukjOO-sNQ8_" - }, - "outputs": [], - "source": [ - "from langchain_google_vertexai import VertexAIEmbeddings, VertexAI\n", - "from langchain.chains import ConversationalRetrievalChain\n", - "from langchain.memory import ConversationSummaryBufferMemory\n", - "from langchain_core.prompts import PromptTemplate\n", - "from langchain_google_cloud_sql_pg import (\n", - " PostgresEngine,\n", - " PostgresVectorStore,\n", - " PostgresChatMessageHistory,\n", - ")\n", - "\n", - "# Initialize the embedding service\n", - "embeddings_service = VertexAIEmbeddings(\n", - " model_name=\"textembedding-gecko@latest\", project=project_id\n", - ")\n", - "\n", - "# Initialize the engine\n", - "pg_engine = PostgresEngine.from_instance(\n", - " project_id=project_id,\n", - " instance=instance_name,\n", - " region=region,\n", - " database=database_name,\n", - " user=\"postgres\",\n", - " password=password,\n", - ")\n", - "\n", - "# Initialize the Vector Store\n", - "vector_table_name = \"movie_vector_table\"\n", - "vector_store = PostgresVectorStore.create_sync(\n", - " engine=pg_engine,\n", - " embedding_service=embeddings_service,\n", - " table_name=vector_table_name,\n", - " metadata_columns=[\n", - " \"show_id\",\n", - " \"type\",\n", - " \"country\",\n", - " \"date_added\",\n", - " \"release_year\",\n", - " \"duration\",\n", - " \"listed_in\",\n", - " ],\n", - ")\n", - "\n", - "# Initialize the PostgresChatMessageHistory\n", - "chat_history = PostgresChatMessageHistory.create_sync(\n", - " pg_engine,\n", - " session_id=\"my-test-session\",\n", - " table_name=\"message_store\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ytlz9D3LmcU7" - }, - "source": [ - "Let's create a prompt for the LLM. Here we can add instructions specific to our application, such as \"Don't make things up\"." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "id": "LoAHNdrWmW9W" - }, - "outputs": [], - "source": [ - "# Prepare some prompt templates for the ConversationalRetrievalChain\n", - "prompt = PromptTemplate(\n", - " template=\"\"\"Use all the information from the context and the conversation history to answer new question. If you see the answer in previous conversation history or the context. \\\n", - "Answer it with clarifying the source information. If you don't see it in the context or the chat history, just say you \\\n", - "didn't find the answer in the given data. Don't make things up.\n", - "\n", - "Previous conversation history from the questioner. \"Human\" was the user who's asking the new question. \"Assistant\" was you as the assistant:\n", - "```{chat_history}\n", - "```\n", - "\n", - "Vector search result of the new question:\n", - "```{context}\n", - "```\n", - "\n", - "New Question:\n", - "```{question}```\n", - "\n", - "Answer:\"\"\",\n", - " input_variables=[\"context\", \"question\", \"chat_history\"],\n", - ")\n", - "condense_question_prompt_passthrough = PromptTemplate(\n", - " template=\"\"\"Repeat the following question:\n", - "{question}\n", - "\"\"\",\n", - " input_variables=[\"question\"],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "rsGe-bW5m0H1" - }, - "source": [ - "Now let's use our vector store as a retreiver. Retreiver's in Langchain allow us to literally \"retrieve\" documents." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "id": "1nI0xkJamvXt" - }, - "outputs": [], - "source": [ - "# Initialize retriever, llm and memory for the chain\n", - "retriever = vector_store.as_retriever(\n", - " search_type=\"mmr\", search_kwargs={\"k\": 5, \"lambda_mult\": 0.8}\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "3maZ8SLlneYJ" - }, - "source": [ - "Now let's initialize our LLM, in this case we are using Vertex AI's \"gemini-pro\"." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "id": "VBWhg-ihnnxF" - }, - "outputs": [], - "source": [ - "llm = VertexAI(model_name=\"gemini-pro\", project=project_id)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hN8mpXdtnocg" - }, - "source": [ - "We clear our chat history, so that our application starts without any prior context to other conversations we have had with the application." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "id": "1UkPcEpJno5Y" - }, - "outputs": [], - "source": [ - "chat_history.clear()\n", - "\n", - "memory = ConversationSummaryBufferMemory(\n", - " llm=llm,\n", - " chat_memory=chat_history,\n", - " output_key=\"answer\",\n", - " memory_key=\"chat_history\",\n", - " return_messages=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "BDAT2koSn8Mz" - }, - "source": [ - "Now let's create a conversational retrieval chain. This will allow the LLM to use chat history in it's responses, meaning we can ask it follow up questions to our questions instead of having to start from scratch after each inquiry." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "7Fu8fKdEn8h8", - "outputId": "abadf0d2-abcd-47a4-d598-45140205593f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Question: What movie was Brad Pitt in?\n", - "Answer: Inglourious Basterds, By the Sea, Killing Them Softly, Babel\n", - "\n", - "Question: How about Jonny Depp?\n", - "Answer: Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\n", - "\n", - "Question: Are there movies about animals?\n", - "Answer: Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat. (Vector search result)\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "[HumanMessage(content='What movie was Brad Pitt in?'),\n", - " AIMessage(content='Inglourious Basterds, By the Sea, Killing Them Softly, Babel'),\n", - " HumanMessage(content='How about Jonny Depp?'),\n", - " AIMessage(content=\"Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\"),\n", - " HumanMessage(content='Are there movies about animals?'),\n", - " AIMessage(content='Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat.'),\n", - " HumanMessage(content='What movie was Brad Pitt in?'),\n", - " AIMessage(content='Inglourious Basterds, By the Sea, Killing Them Softly, Babel'),\n", - " HumanMessage(content='How about Jonny Depp?'),\n", - " AIMessage(content=\"Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\"),\n", - " HumanMessage(content='Are there movies about animals?'),\n", - " AIMessage(content='Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat. (Vector search result)')]" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# create the ConversationalRetrievalChain\n", - "rag_chain = ConversationalRetrievalChain.from_llm(\n", - " llm=llm,\n", - " retriever=retriever,\n", - " verbose=False,\n", - " memory=memory,\n", - " condense_question_prompt=condense_question_prompt_passthrough,\n", - " combine_docs_chain_kwargs={\"prompt\": prompt},\n", - ")\n", - "\n", - "# ask some questions\n", - "q = \"What movie was Brad Pitt in?\"\n", - "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", - "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", - "\n", - "q = \"How about Jonny Depp?\"\n", - "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", - "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", - "\n", - "q = \"Are there movies about animals?\"\n", - "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", - "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", - "\n", - "# browser the chat history\n", - "chat_history.messages" - ] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "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.11.5" - } + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6zvUr-Qev6lL" + }, + "outputs": [], + "source": [ + "# Copyright 2024 Google LLC\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ob11AkrStrRI" + }, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/googleapis/langchain-google-cloud-sql-pg-python/blob/main/samples/langchain_quick_start.ipynb)\n", + "\n", + "---\n", + "# **Introduction**\n", + "\n", + "In this codelab, you'll learn how to create a powerful interactive generative AI application using Retrieval Augmented Generation powered by [Cloud SQL for PostgreSQL](https://cloud.google.com/sql/docs/postgres) and [LangChain](https://www.langchain.com/). We will be creating an application grounded in a [Netflix Movie dataset](https://www.kaggle.com/datasets/shivamb/netflix-shows), allowing you to interact with movie data in exciting new ways." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ma6pEng3ypbA" + }, + "source": [ + "## Prerequisites\n", + "\n", + "* A basic understanding of the Google Cloud Console\n", + "* Basic skills in command line interface and Google Cloud shell\n", + "* Basic python knowledge" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DzDgqJHgysy1" + }, + "source": [ + "## What you'll learn\n", + "\n", + "* How to deploy a Cloud SQL for PostgreSQL instance\n", + "* How to use Cloud SQL for PostgreSQL as a DocumentLoader\n", + "* How to use Cloud SQL for PostgreSQL as a VectorStore\n", + "* How to use Cloud SQL for PostgreSQL for ChatMessageHistory storage" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FbcZUjT1yvTq" + }, + "source": [ + "## What you'll need\n", + "* A Google Cloud Account and Google Cloud Project\n", + "* A web browser such as [Chrome](https://www.google.com/chrome/)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vHdR4fF3vLWA" + }, + "source": [ + "# **Setup and Requirements**\n", + "\n", + "In the following instructions you will learn to:\n", + "1. Install required dependencies for our application\n", + "2. Set up authentication for our project\n", + "3. Set up a Cloud SQL for PostgreSQL Instance\n", + "4. Import the data used by our application" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uy9KqgPQ4GBi" + }, + "source": [ + "## Install dependencies\n", + "First you will need to install the dependencies needed to run this demo app." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "M_ppDxYf4Gqs" + }, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchain-google-cloud-sql-pg langchain-google-vertexai langchain" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Colab only:** Uncomment the following cell to restart the kernel or use the button to restart the kernel. For Vertex AI Workbench you can restart the terminal using the button on top." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Automatically restart kernel after installs so that your environment can access the new packages\n", + "import IPython\n", + "\n", + "app = IPython.Application.instance()\n", + "app.kernel.do_shutdown(True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DeUbHclxw7_l" + }, + "source": [ + "## Authenticate to Google Cloud within Colab\n", + "In order to access your Google Cloud Project from this notebook, you will need to Authenticate as an IAM user." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "a168rJE1xDHO" + }, + "outputs": [], + "source": [ + "from google.colab import auth\n", + "\n", + "auth.authenticate_user()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UCiNGP1Qxd6x" + }, + "source": [ + "## Connect Your Google Cloud Project\n", + "Time to connect your Google Cloud Project to this notebook so that you can leverage Google Cloud from within Colab." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "qjFuhRhVxlWP" + }, + "outputs": [], + "source": [ + "# @markdown Please fill in the value below with your GCP project ID and then run the cell.\n", + "\n", + "# Please fill in these values.\n", + "project_id = \"\" # @param {type:\"string\"}\n", + "\n", + "# Quick input validations.\n", + "assert project_id, \"⚠️ Please provide a Google Cloud project ID\"\n", + "\n", + "# Configure gcloud.\n", + "!gcloud config set project {project_id}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "O-oqMC5Ox-ZM" + }, + "source": [ + "## Configure Your Google Cloud Project\n", + "\n", + "Configure the following in your Google Cloud Project." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. IAM principal (user, service account, etc.) with the [Cloud SQL Client][client-role] role. The user logged into this notebook will be used as the IAM principal and will be granted the Cloud SQL Client role.\n", + "\n", + "[client-role]: https://cloud.google.com/sql/docs/mysql/roles-and-permissions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "current_user = !gcloud auth list --filter=status:ACTIVE --format=\"value(account)\"\n", + "!gcloud projects add-iam-policy-binding {project_id} \\\n", + " --member=user:{current_user[0]} \\\n", + " --role=\"roles/cloudsql.client\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Enable the APIs for Cloud SQL and Vertex AI within your project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CKWrwyfzyTwH" + }, + "outputs": [], + "source": [ + "# Enable GCP services\n", + "!gcloud services enable sqladmin.googleapis.com aiplatform.googleapis.com" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gn8g7-wCyZU6" + }, + "source": [ + "## Set up Cloud SQL\n", + "You will need a **Postgres** Cloud SQL instance for the following stages of this notebook." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "T616pEOUygYQ" + }, + "source": [ + "### Create a Postgres Instance\n", + "Running the below cell will verify the existence of the Cloud SQL instance and or create a new instance and database if one does not exist.\n", + "\n", + "> ⏳ - Creating a Cloud SQL instance may take a few minutes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "XXI1uUu3y8gc" + }, + "outputs": [], + "source": [ + "#@markdown Please fill in the both the Google Cloud region and name of your Cloud SQL instance. Once filled in, run the cell.\n", + "\n", + "# Please fill in these values.\n", + "region = \"us-central1\" #@param {type:\"string\"}\n", + "instance_name = \"langchain-quickstart-instance\" #@param {type:\"string\"}\n", + "database_name = \"langchain-quickstart-db\" #@param {type:\"string\"}\n", + "password = input(\"Please provide a password to be used for 'postgres' database user: \")\n", + "\n", + "# Quick input validations.\n", + "assert region, \"⚠️ Please provide a Google Cloud region\"\n", + "assert instance_name, \"⚠️ Please provide the name of your instance\"\n", + "assert database_name, \"⚠️ Please provide the name of your database_name\"\n", + "\n", + "# check if Cloud SQL instance exists in the provided region\n", + "database_version = !gcloud sql instances describe {instance_name} --format=\"value(databaseVersion)\"\n", + "if database_version[0].startswith(\"POSTGRES\"):\n", + " print(\"Found existing Postgres Cloud SQL Instance!\")\n", + "else:\n", + " print(\"Creating new Cloud SQL instance...\")\n", + " !gcloud sql instances create {instance_name} --database-version=POSTGRES_15 \\\n", + " --region={region} --cpu=1 --memory=4GB --root-password={password} \\\n", + " --database-flags=cloudsql.iam_authentication=On\n", + " !gcloud sql databases create {database_name} --instance={instance_name}\n", + "\n", + "\n", + "databases = !gcloud sql databases list --instance={instance_name} --format=\"value(name)\"\n", + "if database_name not in databases:\n", + " !gcloud sql databases create {database_name} --instance={instance_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HdolCWyatZmG" + }, + "source": [ + "## Import data to your database\n", + "\n", + "Now that you have your database, you will need to import data! We will be using a [Netflix Dataset from Kaggle](https://www.kaggle.com/datasets/shivamb/netflix-shows). Here is what the data looks like:" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "36-FBKzJ-tLa" + }, + "source": [ + "| show_id | type | title | director | cast | country | date_added | release_year | rating | duration | listed_in | description |\n", + "|---------|---------|----------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-------------------|--------------|--------|-----------|----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n", + "| s1 | Movie | Dick Johnson Is Dead | Kirsten Johnson | | United States | September 25, 2021 | 2020 | PG-13 | 90 min | Documentaries | As her father nears the end of his life, filmmaker Kirsten Johnson stages his death in inventive and comical ways to help them both face the inevitable. |\n", + "| s2 | TV Show | Blood & Water | | Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile Tshabalala, Getmore Sithole, Cindy Mahlangu, Ryle De Morny, Greteli Fincham, Sello Maake Ka-Ncube, Odwa Gwanya, Mekaila Mathys, Sandi Schultz, Duane Williams, Shamilla Miller, Patrick Mofokeng | South Africa | September 24, 2021 | 2021 | TV-MA | 2 Seasons | International TV Shows, TV Dramas, TV Mysteries | After crossing paths at a party, a Cape Town teen sets out to prove whether a private-school swimming star is her sister who was abducted at birth. |\n", + "| s3 | TV Show | Ganglands | Julien Leclercq | Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, Geert Van Rampelberg, Bakary Diombera | | September 24, 2021 | 2021 | TV-MA | 1 Season | Crime TV Shows, International TV Shows, TV Action & Adventure | To protect his family from a powerful drug lord, skilled thief Mehdi and his expert team of robbers are pulled into a violent and deadly turf war. |\n", + "| s4 | TV Show | Jailbirds New Orleans | | | | September 24, 2021 | 2021 | TV-MA | 1 Season | Docuseries, Reality TV | Feuds, flirtations and toilet talk go down among the incarcerated women at the Orleans Justice Center in New Orleans on this gritty reality series. |\n", + "| s5 | TV Show | Kota Factory | | Mayur More, Jitendra Kumar, Ranjan Raj, Alam Khan, Ahsaas Channa, Revathi Pillai, Urvi Singh, Arun Kumar | India | September 24, 2021 | 2021 | TV-MA | 2 Seasons | International TV Shows, Romantic TV Shows, TV Comedies | In a city of coaching centers known to train India’s finest collegiate minds, an earnest but unexceptional student and his friends navigate campus life. |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kQ2KWsYI_Msa" + }, + "source": [ + "You won't need to directly load the csv data into your database. Instead we prepared a table, \"netflix_titles\", in the format of a `.sql` file for Postgres. You can easily import the table into your database with one `gcloud` command." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qbLhv9jgD8nm" + }, + "outputs": [], + "source": [ + "# Import the Netflix titles table using gcloud command\n", + "import_command_output = !gcloud sql import sql {instance_name} gs://cloud-samples-data/langchain/cloud-sql/postgres/first_five_netflix_titles.sql --database={database_name} --quiet\n", + "\n", + "if \"Imported data\" in str(import_command_output):\n", + " print(import_command_output)\n", + "elif \"already exists\" in str(import_command_output):\n", + " print(\"Did not import because the table already existed.\")\n", + "else:\n", + " raise Exception(f\"The import seems failed:\\n{import_command_output}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SsGS80H04bDN" + }, + "source": [ + "# **Use case 1: Cloud SQL for PostgreSQL as a document loader**\n", + "\n", + "Now that you have data in your database, you are ready to use Cloud SQL for PostgreSQL as a [document loader](https://python.langchain.com/docs/modules/data_connection/document_loaders/). This means we will pull data from the database and load it into memory as documents. We can then feed these documents into the vector store." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-CQgPON8dwSK" + }, + "source": [ + "Next let's connect to our CloudSQL PostgreSQL instance using the PostgresEngine class.\n", + "\n", + "To connect to your Cloud SQL instance from this notebook, you will need to enable public IP on your instance. Alternatively, you can follow [these instructions](https://cloud.google.com/sql/docs/postgres/connect-to-instance-from-outside-vpc) to connect to an Cloud SQL for PostgreSQL instance with Private IP from outside your VPC. Learn more about [specifying IP types](https://github.com/GoogleCloudPlatform/cloud-sql-python-connector?tab=readme-ov-file#specifying-ip-address-type)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zrwTsWHMkQ_v" + }, + "outputs": [], + "source": [ + "from langchain_google_cloud_sql_pg import PostgresLoader, PostgresEngine, Column\n", + "\n", + "pg_engine = PostgresEngine.from_instance(\n", + " project_id=project_id,\n", + " instance=instance_name,\n", + " region=region,\n", + " database=database_name,\n", + " user=\"postgres\",\n", + " password=password,\n", + " ip_type=\"public\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8s-C0P-Oee69" + }, + "source": [ + "Once we initialize a PostgresEngine object, we can pass it into the PostgresLoader to connect to a specific database. As you can see we also pass in a query, table_name and a list of columns. The query tells the loader what query to use to pull data. The \"content_columns\" argument refers to the columns that will be used as \"content\" in the document object we will later construct. The rest of the columns in that table will become the \"metadata\" associated with the documents." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "2SdFJT6Vece1" + }, + "outputs": [], + "source": [ + "table_name = \"netflix_titles\"\n", + "content_columns = [\"title\", \"director\", \"cast\", \"description\"]\n", + "loader = await PostgresLoader.create(\n", + " engine=pg_engine,\n", + " query=f\"SELECT * FROM {table_name};\",\n", + " content_columns=content_columns,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dsL-KFrmfuS1" + }, + "source": [ + "Then let's run the function to pull our documents from out database using our document loader. You can see the first 5 documents from the database here. Nice, you just used CloudSQL for PostgreSQL as a document loader!" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file + "id": "t4zTx-HLfwmW", + "outputId": "da7239e4-710d-43ce-c004-520a0af9c79f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loaded 8802 from the database. 5 Examples:\n", + "page_content='Midnight Mass Mike Flanagan Kate Siegel, Zach Gilford, Hamish Linklater, Henry Thomas, Kristin Lehman, Samantha Sloyan, Igby Rigney, Rahul Kohli, Annarah Cymone, Annabeth Gish, Alex Essoe, Rahul Abburi, Matt Biedel, Michael Trucco, Crystal Balint, Louis Oliver The arrival of a charismatic young priest brings glorious miracles, ominous mysteries and renewed religious fervor to a dying town desperate to believe.' metadata={'show_id': 's6', 'type': 'TV Show', 'country': None, 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'TV-MA', 'duration': '1 Season', 'listed_in': 'TV Dramas, TV Horror, TV Mysteries'}\n", + "page_content=\"My Little Pony: A New Generation Robert Cullen, José Luis Ucha Vanessa Hudgens, Kimiko Glenn, James Marsden, Sofia Carson, Liza Koshy, Ken Jeong, Elizabeth Perkins, Jane Krakowski, Michael McKean, Phil LaMarr Equestria's divided. But a bright-eyed hero believes Earth Ponies, Pegasi and Unicorns should be pals — and, hoof to heart, she’s determined to prove it.\" metadata={'show_id': 's7', 'type': 'Movie', 'country': None, 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'PG', 'duration': '91 min', 'listed_in': 'Children & Family Movies'}\n", + "page_content='Sankofa Haile Gerima Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri On a photo shoot in Ghana, an American model slips back in time, becomes enslaved on a plantation and bears witness to the agony of her ancestral past.' metadata={'show_id': 's8', 'type': 'Movie', 'country': 'United States, Ghana, Burkina Faso, United Kingdom, Germany, Ethiopia', 'date_added': 'September 24, 2021', 'release_year': 1993, 'rating': 'TV-MA', 'duration': '125 min', 'listed_in': 'Dramas, Independent Movies, International Movies'}\n", + "page_content=\"The Great British Baking Show Andy Devonshire Mel Giedroyc, Sue Perkins, Mary Berry, Paul Hollywood A talented batch of amateur bakers face off in a 10-week competition, whipping up their best dishes in the hopes of being named the U.K.'s best.\" metadata={'show_id': 's9', 'type': 'TV Show', 'country': 'United Kingdom', 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'TV-14', 'duration': '9 Seasons', 'listed_in': 'British TV Shows, Reality TV'}\n", + "page_content=\"The Starling Theodore Melfi Melissa McCarthy, Chris O'Dowd, Kevin Kline, Timothy Olyphant, Daveed Diggs, Skyler Gisondo, Laura Harrier, Rosalind Chao, Kimberly Quinn, Loretta Devine, Ravi Kapoor A woman adjusting to life after a loss contends with a feisty bird that's taken over her garden — and a husband who's struggling to find a way forward.\" metadata={'show_id': 's10', 'type': 'Movie', 'country': 'United States', 'date_added': 'September 24, 2021', 'release_year': 2021, 'rating': 'PG-13', 'duration': '104 min', 'listed_in': 'Comedies, Dramas'}\n" + ] + } + ], + "source": [ + "documents = await loader.aload()\n", + "print(f\"Loaded {len(documents)} from the database. 5 Examples:\")\n", + "for doc in documents[:5]:\n", + " print(doc)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "z9uLV3bs4noo" + }, + "source": [ + "# **Use case 2: Cloud SQL for PostgreSQL as Vector Store**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "duVsSeMcgEWl" + }, + "source": [ + "Now, let's learn how to put all of the documents we just loaded into a [vector store](https://python.langchain.com/docs/modules/data_connection/vectorstores/) so that we can use vector search to answer our user's questions!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jfH8oQJ945Ko" + }, + "source": [ + "### Create Your Vector Store table\n", + "\n", + "Based on the documents that we loaded before, we want to create a table with a vector column as our vector store. We will start it by intializing a vector table by calling the `init_vectorstore_table` function from our `engine`. As you can see we list all of the columns for our metadata. We also specify a vector size, 768, that corresponds with the length of the vectors computed by the model our embeddings service uses, Vertex AI's textembedding-gecko.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "id": "e_rmjywG47pv" + }, + "outputs": [], + "source": [ + "from langchain_google_cloud_sql_pg import PostgresEngine, Column\n", + "\n", + "sample_vector_table_name = \"movie_vector_table_samples\"\n", + "\n", + "pg_engine = PostgresEngine.from_instance(\n", + " project_id=project_id,\n", + " instance=instance_name,\n", + " region=region,\n", + " database=database_name,\n", + " user=\"postgres\",\n", + " password=password,\n", + ")\n", + "\n", + "pg_engine.init_vectorstore_table(\n", + " sample_vector_table_name,\n", + " vector_size=768,\n", + " metadata_columns=[\n", + " Column(\"show_id\", \"VARCHAR\", nullable=True),\n", + " Column(\"type\", \"VARCHAR\", nullable=True),\n", + " Column(\"country\", \"VARCHAR\", nullable=True),\n", + " Column(\"date_added\", \"VARCHAR\", nullable=True),\n", + " Column(\"release_year\", \"INTEGER\", nullable=True),\n", + " Column(\"rating\", \"VARCHAR\", nullable=True),\n", + " Column(\"duration\", \"VARCHAR\", nullable=True),\n", + " Column(\"listed_in\", \"VARCHAR\", nullable=True),\n", + " ],\n", + " overwrite_existing=True, # Enabling this will recreate the table if exists.\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KG6rwEuJLNIo" + }, + "source": [ + "### Try inserting the documents into the vector table\n", + "\n", + "Now we will create a vector_store object backed by our vector table in the Cloud SQL database. Let's load the data from the documents to the vector table. Note that for each row, the embedding service will be called to compute the embeddings to store in the vector table. Pricing details can be found [here](https://cloud.google.com/vertex-ai/pricing)." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "id": "Wo4-7EYCIFF9" + }, + "outputs": [], + "source": [ + "from langchain_google_vertexai import VertexAIEmbeddings\n", + "from langchain_google_cloud_sql_pg import PostgresVectorStore\n", + "\n", + "# Initialize the embedding service. In this case we are using version 003 of Vertex AI's textembedding-gecko model. In general, it is good practice to specify the model version used.\n", + "embeddings_service = VertexAIEmbeddings(\n", + " model_name=\"textembedding-gecko@003\", project=project_id\n", + ")\n", + "\n", + "vector_store = PostgresVectorStore.create_sync(\n", + " engine=pg_engine,\n", + " embedding_service=embeddings_service,\n", + " table_name=sample_vector_table_name,\n", + " metadata_columns=[\n", + " \"show_id\",\n", + " \"type\",\n", + " \"country\",\n", + " \"date_added\",\n", + " \"release_year\",\n", + " \"duration\",\n", + " \"listed_in\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fr1rP6KQ-8ag" + }, + "source": [ + "Now let's try to put the documents data into the vector table. Here is a code example to load the first 5 documents in the list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CTks8Cy--93B" + }, + "outputs": [], + "source": [ + "import uuid\n", + "\n", + "docs_to_load = documents[:5]\n", + "\n", + "# ! Uncomment the following line to load all 8,800+ documents to the database vector table with calling the embedding service.\n", + "# docs_to_load = documents\n", + "\n", + "ids = [str(uuid.uuid4()) for i in range(len(docs_to_load))]\n", + "vector_store.add_documents(docs_to_load, ids)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "29iztdvfL2BN" + }, + "source": [ + "### Import the rest of your data into your vector table\n", + "\n", + "You don't have to call the embedding service 8,800 times to load all the documents for the demo. Instead, we have prepared a table with the all 8,800+ rows with pre-computed embeddings in a `.sql` file. Again, let's import to our DB using `gcloud` command.\n", + "\n", + "It will restore the `.sql` file to a table with vectors called `movie_vector_table`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FEe9El7QMjHi" + }, + "outputs": [], + "source": [ + "# Import the netflix titles with vector table using gcloud command\n", + "import_command_output = !gcloud sql import sql {instance_name} gs://cloud-samples-data/langchain/cloud-sql/postgres/netflix_titles_vector_table.sql --database={database_name} --quiet\n", + "\n", + "if \"Imported data\" in str(import_command_output):\n", + " print(import_command_output)\n", + "elif \"already exists\" in str(import_command_output):\n", + " print(\"Did not import because the table already existed.\")\n", + "else:\n", + " raise Exception(f\"The import seems failed:\\n{import_command_output}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZM_OFzZrQEPs" + }, + "source": [ + "# **Use case 3: Cloud SQL for PostgreSQL as Chat Memory**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dxqIPQtjDquk" + }, + "source": [ + "Next we will add chat history (called [“memory” in the context of LangChain](https://python.langchain.com/docs/modules/memory/)) to our application so the LLM can retain context and information across multiple interactions, leading to more coherent and sophisticated conversations or text generation. We can use Cloud SQL for PostgreSQL as “memory” storage in our application so that the LLM can use context from prior conversations to better answer the user’s prompts. First let's initialize Cloud SQL for PostgreSQL as memory storage." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "vyYQILyoEAqg" + }, + "outputs": [], + "source": [ + "from langchain_google_cloud_sql_pg import PostgresChatMessageHistory, PostgresEngine\n", + "\n", + "message_table_name = \"message_store\"\n", + "\n", + "pg_engine.init_chat_history_table(table_name=message_table_name)\n", + "\n", + "chat_history = PostgresChatMessageHistory.create_sync(\n", + " pg_engine,\n", + " session_id=\"my-test-session\",\n", + " table_name=message_table_name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2yuXYLTCl2K1" + }, + "source": [ + "Here is an example of how you would add a user message and how you would add an ai message." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qDVoTWZal0ZF", + "outputId": "aeb8c338-9f0d-4143-c09d-9c49478940e0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[HumanMessage(content='What movie was Brad Pitt in?'),\n", + " AIMessage(content='Brad Pitt was in Inglourious Basterds, By the Sea, Killing Them Softly and Babel according to the given data.'),\n", + " HumanMessage(content='How about Jonny Depp?'),\n", + " AIMessage(content=\"Jonny Depp was in Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, and What's Eating Gilbert Grape according to the given data.\"),\n", + " HumanMessage(content='Are there movies about animals?'),\n", + " AIMessage(content='Yes, Rango features animals.'),\n", + " HumanMessage(content='Hi!'),\n", + " AIMessage(content=\"Hello there. I'm a model and am happy to help!\")]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chat_history.add_user_message(\"Hi!\")\n", + "chat_history.add_ai_message(\"Hello there. I'm a model and am happy to help!\")\n", + "\n", + "chat_history.messages" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k0O9mta8RQ0v" + }, + "source": [ + "# **Conversational RAG Chain backed by Cloud SQL Postgres**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j2OxF3JoNA7J" + }, + "source": [ + "So far we've tested with using Cloud SQL for PostgreSQL as document loader, Vector Store and Chat Memory. Now let's use it in the `ConversationalRetrievalChain`.\n", + "\n", + "We will build a chat bot that can answer movie related questions based on the vector search results.\n", + "\n", + "First let's initialize all of our PostgresSQLEngine object to use as a connection in our vector store and chat_history." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "9ukjOO-sNQ8_" + }, + "outputs": [], + "source": [ + "from langchain_google_vertexai import VertexAIEmbeddings, VertexAI\n", + "from langchain.chains import ConversationalRetrievalChain\n", + "from langchain.memory import ConversationSummaryBufferMemory\n", + "from langchain_core.prompts import PromptTemplate\n", + "from langchain_google_cloud_sql_pg import (\n", + " PostgresEngine,\n", + " PostgresVectorStore,\n", + " PostgresChatMessageHistory,\n", + ")\n", + "\n", + "# Initialize the embedding service\n", + "embeddings_service = VertexAIEmbeddings(\n", + " model_name=\"textembedding-gecko@latest\", project=project_id\n", + ")\n", + "\n", + "# Initialize the engine\n", + "pg_engine = PostgresEngine.from_instance(\n", + " project_id=project_id,\n", + " instance=instance_name,\n", + " region=region,\n", + " database=database_name,\n", + " user=\"postgres\",\n", + " password=password,\n", + ")\n", + "\n", + "# Initialize the Vector Store\n", + "vector_table_name = \"movie_vector_table\"\n", + "vector_store = PostgresVectorStore.create_sync(\n", + " engine=pg_engine,\n", + " embedding_service=embeddings_service,\n", + " table_name=vector_table_name,\n", + " metadata_columns=[\n", + " \"show_id\",\n", + " \"type\",\n", + " \"country\",\n", + " \"date_added\",\n", + " \"release_year\",\n", + " \"duration\",\n", + " \"listed_in\",\n", + " ],\n", + ")\n", + "\n", + "# Initialize the PostgresChatMessageHistory\n", + "chat_history = PostgresChatMessageHistory.create_sync(\n", + " pg_engine,\n", + " session_id=\"my-test-session\",\n", + " table_name=\"message_store\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ytlz9D3LmcU7" + }, + "source": [ + "Let's create a prompt for the LLM. Here we can add instructions specific to our application, such as \"Don't make things up\"." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "id": "LoAHNdrWmW9W" + }, + "outputs": [], + "source": [ + "# Prepare some prompt templates for the ConversationalRetrievalChain\n", + "prompt = PromptTemplate(\n", + " template=\"\"\"Use all the information from the context and the conversation history to answer new question. If you see the answer in previous conversation history or the context. \\\n", + "Answer it with clarifying the source information. If you don't see it in the context or the chat history, just say you \\\n", + "didn't find the answer in the given data. Don't make things up.\n", + "\n", + "Previous conversation history from the questioner. \"Human\" was the user who's asking the new question. \"Assistant\" was you as the assistant:\n", + "```{chat_history}\n", + "```\n", + "\n", + "Vector search result of the new question:\n", + "```{context}\n", + "```\n", + "\n", + "New Question:\n", + "```{question}```\n", + "\n", + "Answer:\"\"\",\n", + " input_variables=[\"context\", \"question\", \"chat_history\"],\n", + ")\n", + "condense_question_prompt_passthrough = PromptTemplate(\n", + " template=\"\"\"Repeat the following question:\n", + "{question}\n", + "\"\"\",\n", + " input_variables=[\"question\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rsGe-bW5m0H1" + }, + "source": [ + "Now let's use our vector store as a retreiver. Retreiver's in Langchain allow us to literally \"retrieve\" documents." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "id": "1nI0xkJamvXt" + }, + "outputs": [], + "source": [ + "# Initialize retriever, llm and memory for the chain\n", + "retriever = vector_store.as_retriever(\n", + " search_type=\"mmr\", search_kwargs={\"k\": 5, \"lambda_mult\": 0.8}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3maZ8SLlneYJ" + }, + "source": [ + "Now let's initialize our LLM, in this case we are using Vertex AI's \"gemini-pro\"." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "id": "VBWhg-ihnnxF" + }, + "outputs": [], + "source": [ + "llm = VertexAI(model_name=\"gemini-pro\", project=project_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hN8mpXdtnocg" + }, + "source": [ + "We clear our chat history, so that our application starts without any prior context to other conversations we have had with the application." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "1UkPcEpJno5Y" + }, + "outputs": [], + "source": [ + "chat_history.clear()\n", + "\n", + "memory = ConversationSummaryBufferMemory(\n", + " llm=llm,\n", + " chat_memory=chat_history,\n", + " output_key=\"answer\",\n", + " memory_key=\"chat_history\",\n", + " return_messages=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BDAT2koSn8Mz" + }, + "source": [ + "Now let's create a conversational retrieval chain. This will allow the LLM to use chat history in it's responses, meaning we can ask it follow up questions to our questions instead of having to start from scratch after each inquiry." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7Fu8fKdEn8h8", + "outputId": "abadf0d2-abcd-47a4-d598-45140205593f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Question: What movie was Brad Pitt in?\n", + "Answer: Inglourious Basterds, By the Sea, Killing Them Softly, Babel\n", + "\n", + "Question: How about Jonny Depp?\n", + "Answer: Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\n", + "\n", + "Question: Are there movies about animals?\n", + "Answer: Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat. (Vector search result)\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "[HumanMessage(content='What movie was Brad Pitt in?'),\n", + " AIMessage(content='Inglourious Basterds, By the Sea, Killing Them Softly, Babel'),\n", + " HumanMessage(content='How about Jonny Depp?'),\n", + " AIMessage(content=\"Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\"),\n", + " HumanMessage(content='Are there movies about animals?'),\n", + " AIMessage(content='Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat.'),\n", + " HumanMessage(content='What movie was Brad Pitt in?'),\n", + " AIMessage(content='Inglourious Basterds, By the Sea, Killing Them Softly, Babel'),\n", + " HumanMessage(content='How about Jonny Depp?'),\n", + " AIMessage(content=\"Charlie and the Chocolate Factory, The Rum Diary, The Imaginarium of Doctor Parnassus, What's Eating Gilbert Grape (Vector search result)\"),\n", + " HumanMessage(content='Are there movies about animals?'),\n", + " AIMessage(content='Yes, there are movies about animals. For example, \"Animals on the Loose: A You vs. Wild Movie\" is an interactive special where you and Bear Grylls must pursue escaped wild animals and secure their protective habitat. (Vector search result)')]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# create the ConversationalRetrievalChain\n", + "rag_chain = ConversationalRetrievalChain.from_llm(\n", + " llm=llm,\n", + " retriever=retriever,\n", + " verbose=False,\n", + " memory=memory,\n", + " condense_question_prompt=condense_question_prompt_passthrough,\n", + " combine_docs_chain_kwargs={\"prompt\": prompt},\n", + ")\n", + "\n", + "# ask some questions\n", + "q = \"What movie was Brad Pitt in?\"\n", + "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", + "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", + "\n", + "q = \"How about Jonny Depp?\"\n", + "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", + "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", + "\n", + "q = \"Are there movies about animals?\"\n", + "ans = rag_chain({\"question\": q, \"chat_history\": chat_history})[\"answer\"]\n", + "print(f\"Question: {q}\\nAnswer: {ans}\\n\")\n", + "\n", + "# browser the chat history\n", + "chat_history.messages" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}