diff --git a/docs/_toc.yml b/docs/_toc.yml index ae1a4950f4..0cbe86516f 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -18,6 +18,8 @@ parts: title: Image Search [FAISS] - file: source/usecases/qa-video.rst title: Q&A from Videos [ChatGPT + HuggingFace] + - file: source/usecases/food-review.rst + title: Sentiment Analysis and Response [ChatGPT + PostgreSQL] - file: source/usecases/02-object-detection.ipynb title: Object Detection - file: source/usecases/03-emotion-analysis.ipynb diff --git a/docs/source/usecases/food-review.rst b/docs/source/usecases/food-review.rst new file mode 100644 index 0000000000..77493e7cb4 --- /dev/null +++ b/docs/source/usecases/food-review.rst @@ -0,0 +1,147 @@ +ChatGPT + Postgres Tutorial +=========================== + +.. raw:: html + + + + + + +
+ Run on Google Colab + + View source on GitHub + + Download notebook +


+ + +In this tutorial, we demonstrate how to use EvaDB + ChatGPT to analyze the tone of food reviews stored in PostgreSQL. Then, based on the analysis, we further use +EvaDB + ChatGPT to address negative reviews by proposing a solution to the customer. + +For this use case, we assume user has a Postgres server running locally. You can also check our notebook above to skip Postgres setup. + +1. Connect to EvaDB +------------------- + +.. code-block:: python + + import evadb + cursor = evadb.connect().cursor() + +2. Connect to an Existing Postgres Database +------------------------------------------- + +.. tab-set:: + + .. tab-item:: Python + + .. code-block:: python + + params = { + "user": "eva", + "password": "password", + "host": "localhost", + "port": "5432", + "database": "evadb", + } + query = f"CREATE DATABASE postgres_data WITH ENGINE = 'postgres', PARAMETERS = {params};" + cursor.query(query).df() + + .. tab-item:: SQL + + .. code-block:: sql + + CREATE DATABASE postgres_data WITH ENGINE = 'postgres', PARAMETERS = { + "user": "eva", + "password": "password", + "host": "localhost", + "port": "5432", + "database": "evadb" + } + +3. Sentiment Analysis of Food Review using ChatGPT +--------------------------------------------- + +We then use EvaDB + ChatGPT to analyze whether the review is "positive" or "negative" with customized ChatGPT prompt. For this use case, +we assume reviews have been already loaded into the table inside PostgreSQL. +You can check our `Jupyter Notebook `_ for how to load data. + +.. tab-set:: + + .. tab-item:: Python + + .. code-block:: python + + cursor.query(""" + SELECT ChatGPT( + "Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.", + review) + FROM postgres_data.review_table; + """).df() + + .. tab-item:: SQL + + .. code-block:: sql + + SELECT ChatGPT( + "Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.", + review) + FROM postgres_data.review_table; + +This will return tone analysis results for existing reviews. + +.. code-block:: + + +------------------------------+ + | chatgpt.response | + |------------------------------| + | negative | + | positive | + | negative | + +------------------------------+ + +4. Response to Negative Reviews using ChatGPT +--------------------------------------------- + +.. tab-set:: + + .. tab-item:: Python + + .. code-block:: python + + cursor.query(""" + SELECT ChatGPT( + "Respond the the review with solution to address the review's concern", + review) + FROM postgres_data.review_table + WHERE ChatGPT( + "Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.", + review) = "negative"; + """).df() + + .. tab-item:: SQL + + .. code-block:: sql + + SELECT ChatGPT( + "Respond the the review with solution to address the review's concern", + review) + FROM postgres_data.review_table + WHERE ChatGPT( + "Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.", + review) = "negative"; + +This query will first filter out positive reviews and then apply ChatGPT again to create response to negative reviews. This will give results. + +.. code-block:: + + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | chatgpt.response | + |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + | Dear valued customer, Thank you for bringing this matter to our attention. We apologize for the inconvenience caused by the excessive saltiness of your fried rice. We understand how important it is to have a satisfying dining experience, and we would like to make it right for you ... | + | Dear [Customer's Name], Thank you for bringing this issue to our attention. We apologize for the inconvenience caused by the missing chicken sandwich in your takeout order. We understand how frustrating it can be when an item is missing from your meal. To address this concern, we ... | + +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Check out our `Jupyter Notebook `_ for working example. \ No newline at end of file diff --git a/tutorials/14-food-review-tone-analysis-and-response.ipynb b/tutorials/14-food-review-tone-analysis-and-response.ipynb new file mode 100644 index 0000000000..2c659fd605 --- /dev/null +++ b/tutorials/14-food-review-tone-analysis-and-response.ipynb @@ -0,0 +1,1634 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "nQ7xbeAhW56k" + }, + "source": [ + "# Food Review Tone Analysis and Response\n", + "In this tutorial, we use EvaDB + ChatGPT to analyze whether a food review is negative or not. Based on the analysis, we then use EvaDB + ChatGPT again to form a polite response to address negative review." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + "
\n", + " Run on Google Colab\n", + " \n", + " View source on GitHub\n", + " \n", + " Download notebook\n", + "


" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "u4duS22nW56m" + }, + "source": [ + "## Start Postgres" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iwWMlVaVaOuH", + "outputId": "41d6f054-4257-4d54-dba0-ffc7098a8c6d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading package lists... Done\n", + "Building dependency tree... Done\n", + "Reading state information... Done\n", + "The following additional packages will be installed:\n", + " libcommon-sense-perl libjson-perl libjson-xs-perl libtypes-serialiser-perl\n", + " logrotate netbase postgresql-14 postgresql-client-14\n", + " postgresql-client-common postgresql-common ssl-cert sysstat\n", + "Suggested packages:\n", + " bsd-mailx | mailx postgresql-doc postgresql-doc-14 isag\n", + "The following NEW packages will be installed:\n", + " libcommon-sense-perl libjson-perl libjson-xs-perl libtypes-serialiser-perl\n", + " logrotate netbase postgresql postgresql-14 postgresql-client-14\n", + " postgresql-client-common postgresql-common ssl-cert sysstat\n", + "0 upgraded, 13 newly installed, 0 to remove and 16 not upgraded.\n", + "Need to get 18.3 MB of archives.\n", + "After this operation, 51.5 MB of additional disk space will be used.\n", + "Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 logrotate amd64 3.19.0-1ubuntu1.1 [54.3 kB]\n", + "Get:2 http://archive.ubuntu.com/ubuntu jammy/main amd64 netbase all 6.3 [12.9 kB]\n", + "Get:3 http://archive.ubuntu.com/ubuntu jammy/main amd64 libcommon-sense-perl amd64 3.75-2build1 [21.1 kB]\n", + "Get:4 http://archive.ubuntu.com/ubuntu jammy/main amd64 libjson-perl all 4.04000-1 [81.8 kB]\n", + "Get:5 http://archive.ubuntu.com/ubuntu jammy/main amd64 libtypes-serialiser-perl all 1.01-1 [11.6 kB]\n", + "Get:6 http://archive.ubuntu.com/ubuntu jammy/main amd64 libjson-xs-perl amd64 4.030-1build3 [87.2 kB]\n", + "Get:7 http://archive.ubuntu.com/ubuntu jammy/main amd64 postgresql-client-common all 238 [29.6 kB]\n", + "Get:8 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 postgresql-client-14 amd64 14.9-0ubuntu0.22.04.1 [1,222 kB]\n", + "Get:9 http://archive.ubuntu.com/ubuntu jammy/main amd64 ssl-cert all 1.1.2 [17.4 kB]\n", + "Get:10 http://archive.ubuntu.com/ubuntu jammy/main amd64 postgresql-common all 238 [169 kB]\n", + "Get:11 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 postgresql-14 amd64 14.9-0ubuntu0.22.04.1 [16.1 MB]\n", + "Get:12 http://archive.ubuntu.com/ubuntu jammy/main amd64 postgresql all 14+238 [3,288 B]\n", + "Get:13 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 sysstat amd64 12.5.2-2ubuntu0.2 [487 kB]\n", + "Fetched 18.3 MB in 1s (25.2 MB/s)\n", + "Preconfiguring packages ...\n", + "Selecting previously unselected package logrotate.\n", + "(Reading database ... 120831 files and directories currently installed.)\n", + "Preparing to unpack .../00-logrotate_3.19.0-1ubuntu1.1_amd64.deb ...\n", + "Unpacking logrotate (3.19.0-1ubuntu1.1) ...\n", + "Selecting previously unselected package netbase.\n", + "Preparing to unpack .../01-netbase_6.3_all.deb ...\n", + "Unpacking netbase (6.3) ...\n", + "Selecting previously unselected package libcommon-sense-perl:amd64.\n", + "Preparing to unpack .../02-libcommon-sense-perl_3.75-2build1_amd64.deb ...\n", + "Unpacking libcommon-sense-perl:amd64 (3.75-2build1) ...\n", + "Selecting previously unselected package libjson-perl.\n", + "Preparing to unpack .../03-libjson-perl_4.04000-1_all.deb ...\n", + "Unpacking libjson-perl (4.04000-1) ...\n", + "Selecting previously unselected package libtypes-serialiser-perl.\n", + "Preparing to unpack .../04-libtypes-serialiser-perl_1.01-1_all.deb ...\n", + "Unpacking libtypes-serialiser-perl (1.01-1) ...\n", + "Selecting previously unselected package libjson-xs-perl.\n", + "Preparing to unpack .../05-libjson-xs-perl_4.030-1build3_amd64.deb ...\n", + "Unpacking libjson-xs-perl (4.030-1build3) ...\n", + "Selecting previously unselected package postgresql-client-common.\n", + "Preparing to unpack .../06-postgresql-client-common_238_all.deb ...\n", + "Unpacking postgresql-client-common (238) ...\n", + "Selecting previously unselected package postgresql-client-14.\n", + "Preparing to unpack .../07-postgresql-client-14_14.9-0ubuntu0.22.04.1_amd64.deb ...\n", + "Unpacking postgresql-client-14 (14.9-0ubuntu0.22.04.1) ...\n", + "Selecting previously unselected package ssl-cert.\n", + "Preparing to unpack .../08-ssl-cert_1.1.2_all.deb ...\n", + "Unpacking ssl-cert (1.1.2) ...\n", + "Selecting previously unselected package postgresql-common.\n", + "Preparing to unpack .../09-postgresql-common_238_all.deb ...\n", + "Adding 'diversion of /usr/bin/pg_config to /usr/bin/pg_config.libpq-dev by postgresql-common'\n", + "Unpacking postgresql-common (238) ...\n", + "Selecting previously unselected package postgresql-14.\n", + "Preparing to unpack .../10-postgresql-14_14.9-0ubuntu0.22.04.1_amd64.deb ...\n", + "Unpacking postgresql-14 (14.9-0ubuntu0.22.04.1) ...\n", + "Selecting previously unselected package postgresql.\n", + "Preparing to unpack .../11-postgresql_14+238_all.deb ...\n", + "Unpacking postgresql (14+238) ...\n", + "Selecting previously unselected package sysstat.\n", + "Preparing to unpack .../12-sysstat_12.5.2-2ubuntu0.2_amd64.deb ...\n", + "Unpacking sysstat (12.5.2-2ubuntu0.2) ...\n", + "Setting up logrotate (3.19.0-1ubuntu1.1) ...\n", + "Created symlink /etc/systemd/system/timers.target.wants/logrotate.timer → /lib/systemd/system/logrotate.timer.\n", + "Setting up libcommon-sense-perl:amd64 (3.75-2build1) ...\n", + "Setting up ssl-cert (1.1.2) ...\n", + "Setting up libtypes-serialiser-perl (1.01-1) ...\n", + "Setting up libjson-perl (4.04000-1) ...\n", + "Setting up netbase (6.3) ...\n", + "Setting up sysstat (12.5.2-2ubuntu0.2) ...\n", + "\n", + "Creating config file /etc/default/sysstat with new version\n", + "update-alternatives: using /usr/bin/sar.sysstat to provide /usr/bin/sar (sar) in auto mode\n", + "Created symlink /etc/systemd/system/sysstat.service.wants/sysstat-collect.timer → /lib/systemd/system/sysstat-collect.timer.\n", + "Created symlink /etc/systemd/system/sysstat.service.wants/sysstat-summary.timer → /lib/systemd/system/sysstat-summary.timer.\n", + "Created symlink /etc/systemd/system/multi-user.target.wants/sysstat.service → /lib/systemd/system/sysstat.service.\n", + "Setting up postgresql-client-common (238) ...\n", + "Setting up libjson-xs-perl (4.030-1build3) ...\n", + "Setting up postgresql-client-14 (14.9-0ubuntu0.22.04.1) ...\n", + "update-alternatives: using /usr/share/postgresql/14/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode\n", + "Setting up postgresql-common (238) ...\n", + "Adding user postgres to group ssl-cert\n", + "\n", + "Creating config file /etc/postgresql-common/createcluster.conf with new version\n", + "Building PostgreSQL dictionaries from installed myspell/hunspell packages...\n", + "Removing obsolete dictionary files:\n", + "Created symlink /etc/systemd/system/multi-user.target.wants/postgresql.service → /lib/systemd/system/postgresql.service.\n", + "Setting up postgresql-14 (14.9-0ubuntu0.22.04.1) ...\n", + "Creating new PostgreSQL cluster 14/main ...\n", + "/usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/14/main --auth-local peer --auth-host scram-sha-256 --no-instructions\n", + "The files belonging to this database system will be owned by user \"postgres\".\n", + "This user must also own the server process.\n", + "\n", + "The database cluster will be initialized with locale \"en_US.UTF-8\".\n", + "The default database encoding has accordingly been set to \"UTF8\".\n", + "The default text search configuration will be set to \"english\".\n", + "\n", + "Data page checksums are disabled.\n", + "\n", + "fixing permissions on existing directory /var/lib/postgresql/14/main ... ok\n", + "creating subdirectories ... ok\n", + "selecting dynamic shared memory implementation ... posix\n", + "selecting default max_connections ... 100\n", + "selecting default shared_buffers ... 128MB\n", + "selecting default time zone ... Etc/UTC\n", + "creating configuration files ... ok\n", + "running bootstrap script ... ok\n", + "performing post-bootstrap initialization ... ok\n", + "syncing data to disk ... ok\n", + "update-alternatives: using /usr/share/postgresql/14/man/man1/postmaster.1.gz to provide /usr/share/man/man1/postmaster.1.gz (postmaster.1.gz) in auto mode\n", + "invoke-rc.d: could not determine current runlevel\n", + "invoke-rc.d: policy-rc.d denied execution of start.\n", + "Setting up postgresql (14+238) ...\n", + "Processing triggers for man-db (2.10.2-1) ...\n", + " * Starting PostgreSQL 14 database server\n", + " ...done.\n" + ] + } + ], + "source": [ + "!apt install postgresql\n", + "!service postgresql start" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mUndbObdW56m" + }, + "source": [ + "## Create User and Database" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VonZMyLaesil", + "outputId": "f7a47b41-598e-4308-c7aa-4d1ed64fc265" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CREATE ROLE\n", + "CREATE DATABASE\n" + ] + } + ], + "source": [ + "!sudo -u postgres psql -c \"CREATE USER eva WITH SUPERUSER PASSWORD 'password'\"\n", + "!sudo -u postgres psql -c \"CREATE DATABASE evadb\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OQ8JQqqaW56n" + }, + "source": [ + "## Install EvaDB" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "i-pKJsODavE6", + "outputId": "72b71066-df49-47e1-8404-3d5950326c46" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: psycopg2 in /usr/local/lib/python3.10/dist-packages (2.9.7)\n" + ] + } + ], + "source": [ + "%pip install --quiet \"evadb[document]\"\n", + "%pip install psycopg2\n", + "\n", + "import evadb\n", + "cursor = evadb.connect().cursor()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "YT8nVVKoaC_D" + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings(\"ignore\")\n", + "\n", + "from IPython.core.display import display, HTML\n", + "def pretty_print(df):\n", + " return display(HTML( df.to_html().replace(\"\\\\n\",\"
\")))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nnXs1OxpW56o" + }, + "source": [ + "## Create Data Source in EvaDB\n", + "We use data source to connect EvaDB directly to underlying database systems like Postgres." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "PkbSv2gKc5Nd", + "outputId": "0d5863e4-754f-404b-9afd-c8f4530fcf91" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0
0The database postgres_data has been successful...
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " 0\n", + "0 The database postgres_data has been successful..." + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = {\n", + " \"user\": \"eva\",\n", + " \"password\": \"password\",\n", + " \"host\": \"localhost\",\n", + " \"port\": \"5432\",\n", + " \"database\": \"evadb\",\n", + "}\n", + "query = f\"CREATE DATABASE postgres_data WITH ENGINE = 'postgres', PARAMETERS = {params};\"\n", + "cursor.query(query).df()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ew9wsQUwW56p" + }, + "source": [ + "## Create Review Table" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "tt1MB5CrtYHy", + "outputId": "90f9f1e2-fce7-4396-dfa7-81af843e8e45" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
status
0success
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " status\n", + "0 success" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cursor.query(\"\"\"\n", + "USE postgres_data {\n", + " DROP TABLE IF EXISTS review_table\n", + "}\n", + "\"\"\").df()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "BJnQCg7RbImb", + "outputId": "2c46662c-085f-4fce-9e36-16875f3a6426" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
status
0success
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " status\n", + "0 success" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cursor.query(\"\"\"\n", + "USE postgres_data {\n", + " CREATE TABLE review_table (name VARCHAR(10), review VARCHAR(1000))\n", + "}\n", + "\"\"\").df()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HvxsDeaXW56p" + }, + "source": [ + "## Insert Reviews into Postgres\n", + "In this example, we directly insert data into the table for simplicity. We can also load data from files like CSV using Postgres APIs." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "l-pYla7Jugx7", + "outputId": "fff66893-4dcf-4cb6-8fa5-6b5dc7882c42" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
status
0success
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " status\n", + "0 success" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"\"\"\n", + "USE postgres_data {\n", + " INSERT INTO review_table (name, review) VALUES ('Customer 1', 'I ordered fried rice but it is too salty.')\n", + "}\n", + "\"\"\"\n", + "cursor.query(query).df()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "tfKoI3s9fcSa", + "outputId": "04b47285-72d3-4108-c5b8-8bc21fa1da44" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
status
0success
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " status\n", + "0 success" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"\"\"\n", + "USE postgres_data {\n", + " INSERT INTO review_table (name, review) VALUES ('Customer 2', 'I ordered burger. It tastes very good and the service is exceptional.')\n", + "}\n", + "\"\"\"\n", + "cursor.query(query).df()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "id": "Koj8vwWnYEey", + "outputId": "476f1d7c-fd21-4f01-ec86-ef15bd64f16b" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
status
0success
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " status\n", + "0 success" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = \"\"\"\n", + "USE postgres_data {\n", + " INSERT INTO review_table (name, review) VALUES ('Customer 3', 'I ordered a takeout order, but the chicken sandwidth is missing from the order.')\n", + "}\n", + "\"\"\"\n", + "cursor.query(query).df()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zdxBe4yzW56q" + }, + "source": [ + "## Review Table Content\n", + "Now we have 3 reviews from different customers stored in the table." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 143 + }, + "id": "oA_CNDbxveoo", + "outputId": "ca1632b9-db2b-4694-87a1-b0c41184748c" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
review_table.namereview_table.review
0Customer 1ordered fried rice but it is too salty.
1Customer 2I ordered burger. It tastes very good and the ...
2Customer 3I ordered a takeout order, but the chicken san...
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " review_table.name review_table.review\n", + "0 Customer 1 ordered fried rice but it is too salty.\n", + "1 Customer 2 I ordered burger. It tastes very good and the ...\n", + "2 Customer 3 I ordered a takeout order, but the chicken san..." + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cursor.query(\"SELECT * FROM postgres_data.review_table;\").df()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b0p1__K0W56u" + }, + "source": [ + "## Register OpenAI Token" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "rsUHb1_Ih2dE" + }, + "outputs": [], + "source": [ + "import os\n", + "os.environ[\"OPENAI_KEY\"] = \"sk-...\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3bAzB5gfW56u" + }, + "source": [ + "## Tone Analysis for All Reviews\n", + "Here, we use ChatGPT with customized prompt to summarize whether the review tone is \"postive\" or \"negative\"." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 143 + }, + "id": "W8J_N1WPiOVj", + "outputId": "cf7b2383-6cb8-4597-c7e7-505e14dbcac7" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
chatgpt.response
0negative
1positive
2negative
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "text/plain": [ + " chatgpt.response\n", + "0 negative\n", + "1 positive\n", + "2 negative" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cursor.query(\"\"\"\n", + "SELECT ChatGPT(\n", + " \"Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.\",\n", + " review\n", + ")\n", + "FROM postgres_data.review_table;\n", + "\"\"\").df()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "n_0R8dG_W56u" + }, + "source": [ + "## Respond to Negative Reviews\n", + "EvaDB allows users to filter data based on function output. In this query, we construct a query to filter out \"postive\" reviews. We then use a second ChatGPT with customized prompt to propose a solution to address customer's negative reviews politely." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 703 + }, + "id": "QCX7gDJuiV15", + "outputId": "2ceca7cc-c992-492b-9506-c646b681c429" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
chatgpt.response
0Dear valued customer,

Thank you for bringing this matter to our attention. We apologize for the inconvenience caused by the excessive saltiness of your fried rice. We understand how important it is to have a satisfying dining experience, and we would like to make it right for you.

To address your concern, we have taken the following steps:

1. Recipe adjustment: We have reviewed our fried rice recipe and made necessary adjustments to ensure that the saltiness is balanced and meets our customers' expectations.

2. Staff training: We have conducted additional training sessions with our kitchen staff to emphasize the importance of proper seasoning and taste testing before serving any dish.

3. Quality control: Our management team will be implementing stricter quality control measures to ensure that every dish leaving our kitchen meets our high standards.

We would like to invite you to give us another chance to serve you. Please reach out to our customer service team, and we will be more than happy to offer you a replacement dish or a refund for your order. We value your feedback and want to ensure that you have a positive experience with us.

Once again, we apologize for any inconvenience caused, and we appreciate your understanding. We look forward to the opportunity to make it right for you.

Best regards,
[Your Name]
[Restaurant Name]
1Dear [Customer's Name],

Thank you for bringing this issue to our attention. We apologize for the inconvenience caused by the missing chicken sandwich in your takeout order. We understand how frustrating it can be when an item is missing from your meal.

To address this concern, we would like to offer you two possible solutions:

1. Replacement: We can arrange for a new chicken sandwich to be prepared and delivered to your location as soon as possible. Please let us know your preferred time for the replacement.

2. Refund: If you prefer not to receive a replacement, we can issue a refund for the missing chicken sandwich. The refund will be processed through the same payment method used for the original order.

Please let us know which option you would prefer, and we will take immediate action to resolve this issue for you. We value your satisfaction and want to ensure that you have a positive experience with our service.

Once again, we apologize for any inconvenience caused, and we appreciate your understanding. If you have any further questions or concerns, please don't hesitate to reach out to us.

Best regards,
[Your Name]
[Restaurant Name]
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "response_df = cursor.query(\"\"\"\n", + "SELECT ChatGPT(\n", + " \"Respond the the review with solution to address the review's concern\",\n", + " review\n", + ")\n", + "FROM postgres_data.review_table\n", + "WHERE ChatGPT(\n", + " \"Is the review positive or negative. Only reply 'positive' or 'negative'. Here are examples. The food is very bad: negative. The food is very good: postive.\",\n", + " review\n", + ") = \"negative\";\n", + "\"\"\").df()\n", + "\n", + "pretty_print(response_df)" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}