<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: danieltprice</title>
    <description>The latest articles on Forem by danieltprice (@danieltprice).</description>
    <link>https://forem.com/danieltprice</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1038135%2Feac33b75-17d0-4449-adfd-aca8110b0c0f.png</url>
      <title>Forem: danieltprice</title>
      <link>https://forem.com/danieltprice</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/danieltprice"/>
    <language>en</language>
    <item>
      <title>Chat with your holiday song database with Neon Postgres and LangChain</title>
      <dc:creator>danieltprice</dc:creator>
      <pubDate>Sat, 23 Dec 2023 10:32:31 +0000</pubDate>
      <link>https://forem.com/danieltprice/chat-with-your-holiday-song-database-with-neon-postgres-and-langchain-11gk</link>
      <guid>https://forem.com/danieltprice/chat-with-your-holiday-song-database-with-neon-postgres-and-langchain-11gk</guid>
      <description>&lt;p&gt;🎄 &lt;strong&gt;&lt;em&gt;Get in the festive spirit by chatting with a holiday song database&lt;/em&gt;&lt;/strong&gt; 🎁&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iYjZnvZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bb81i9xyd5bex3wm8wm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iYjZnvZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bb81i9xyd5bex3wm8wm1.png" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://console.neon.tech/"&gt;Neon&lt;/a&gt; is serverless Postgres built for the cloud. It has a generous Free Tier and innovative features like database branching and scale-to-zero. You can spin up a database in just a few clicks. It’ll give you a URL for your database, and you’re ready to go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.langchain.com/"&gt;LangChain&lt;/a&gt; is an open-source framework for developing applications powered by Large Language Models (LLMs). With LangChain, you can build applications that give answers or take actions in response to a variety of possible inputs or contexts, like prompt instructions, sample inputs or responses, or any other data that the reactions should be based on.&lt;/p&gt;

&lt;p&gt;For example, with LangChain, you can connect LLMs with a data source such as Neon Postgres and sequence multiple commands (a series of prompts) that use the data source to achieve a desired result.&lt;/p&gt;

&lt;p&gt;In this post, you’ll learn how to create a “Holiday Song” app in Python that lets you ask your database questions about “chart-topping holiday songs” in natural language. The application transforms your question into an SQL query, runs the query, and returns a natural language response based on the query result. This is achieved using Langchain’s &lt;a href="https://python.langchain.com/docs/use_cases/qa_structured/sql#case-2-text-to-sql-query-and-execution"&gt;SQLDatabaseChain&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The application uses a Kaggle dataset called &lt;a href="https://www.kaggle.com/datasets/thedevastator/top-20-holiday-songs-by-position"&gt;Top Holiday Songs by Position Over The Years&lt;/a&gt; (credit to &lt;a href="https://data.world/throwback-thurs"&gt;Throwback Thursday&lt;/a&gt;), which is a collection of the most popular holiday songs appearing on the charts from 2011 to 2018. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You’ll need the following to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://neon.tech/"&gt;Neon account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An OpenAI API key. Instructions for obtaining an OpenAI API key are provided below.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grab your OpenAI API key
&lt;/h2&gt;

&lt;p&gt;The application uses an OpenAI model, which requires an OpenAI API key. If you do not have an OpenAI API key, you can follow these steps to create one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href="https://platform.openai.com/"&gt;https://platform.openai.com/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on your name or icon, located at the top right corner of the page, and select &lt;strong&gt;View API Keys&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Create new secret key&lt;/strong&gt; button to create a new OpenAI API key.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create a directory for your application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir holiday_songs_app
cd holiday_songs_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up your environment
&lt;/h2&gt;

&lt;p&gt;Create and activate a Python virtual environment in your application directory by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install dependencies
&lt;/h2&gt;

&lt;p&gt;Install the following libraries using &lt;code&gt;pip&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install LangChain LangChain-experimental openai python-environ psycopg2-binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a database in Neon
&lt;/h2&gt;

&lt;p&gt;In Neon, create a database named &lt;code&gt;holiday_songs&lt;/code&gt;. You can do this from the Neon Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Neon Console.&lt;/li&gt;
&lt;li&gt;Select a project.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Databases&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the branch where you want to create the database.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New Database&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;holiday_songs&lt;/code&gt; as the database name, and select a database owner.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M6XcDRdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3vfl7aw49i2u2mki4c4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M6XcDRdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3vfl7aw49i2u2mki4c4c.png" alt="Image description" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your database connection string
&lt;/h2&gt;

&lt;p&gt;Grab the connection string for your holiday_songs database. You can copy it from the &lt;strong&gt;Connection Details&lt;/strong&gt; widget on the Neon &lt;strong&gt;Dashboard&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xfjnemAw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hpi9g20xcor8sgasxwn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xfjnemAw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hpi9g20xcor8sgasxwn.png" alt="Image description" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgresql://daniel:************@ep-snowy-lake-123456.us-east-2.aws.neon.tech/holiday_songs?sslmode=require
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up your environment variables
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in your application directory and configure variables for your OpenAI API key and your database connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_KEY=[your_openai_api_key]
DATABASE_URL="postgresql://daniel:************@ep-snowy-lake-123456.us-east-2.aws.neon.tech/holiday_songs?sslmode=require"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a table and insert data
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;db.py&lt;/code&gt; in your application directory and add the following code to connect to your database, create a songs table, and load the songs table with data from a &lt;code&gt;holiday_songs.csv&lt;/code&gt; file hosted on GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import psycopg2
import environ
import requests
import io

# 1. Setup and read the .env file
env = environ.Env()
environ.Env.read_env()

# 2. Establish a connection to the PostgreSQL database
connection_string = env('DATABASE_URL')
conn = psycopg2.connect(connection_string)
cursor = conn.cursor()

# 3. Create the songs table if it doesn't already exist
table_creation_sql = """
CREATE TABLE IF NOT EXISTS public.songs (
    id INT,
    year INT,
    position INT,
    song TEXT,
    artist TEXT,
    chart_date DATE
);
"""
cursor.execute(table_creation_sql)

# 4. Download the holiday_songs.csv file from GitHub
url = "https://github.com/neondatabase/postgres-sample-dbs/raw/main/holiday_songs.csv"
response = requests.get(url)
response.raise_for_status()

# Use StringIO to convert text data into file-like object so it can be read into the database
csv_file = io.StringIO(response.text)

# 5. Load the data from the holiday_songs.csv into the songs table
copy_command = '''
COPY public.songs (id, year, position, song, artist, chart_date)
FROM STDIN WITH (FORMAT CSV, HEADER true, DELIMITER ',');
'''
cursor.copy_expert(copy_command, csv_file)

# 6. Commit any changes and close the connection
conn.commit()
conn.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the db.py script
&lt;/h2&gt;

&lt;p&gt;Run the &lt;code&gt;db.py&lt;/code&gt; script using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python db.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify that the data was loaded by viewing the data in the Neon console. Select &lt;strong&gt;Tables&lt;/strong&gt; from the sidebar, and navigate to the &lt;code&gt;holiday_songs&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L7TJhAuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn705o3huiqf5vttuc15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L7TJhAuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn705o3huiqf5vttuc15.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the SQL database chain
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;app.py&lt;/code&gt; in your application directory and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import environ
import psycopg2
from urllib.parse import urlparse
from langchain.utilities import SQLDatabase
from langchain.llms import OpenAI
from langchain_experimental.sql import SQLDatabaseChain
from langchain.prompts import PromptTemplate

# Set up and read the .env file
env = environ.Env()
environ.Env.read_env()

# Extract connection details from the .env file
connection_string = env('DATABASE_URL')
parsed_uri = urlparse(connection_string)
username = parsed_uri.username
password = parsed_uri.password
host = parsed_uri.hostname
port = parsed_uri.port or 5432
database = parsed_uri.path[1:]  # remove leading '/'

# Setup database
db = SQLDatabase.from_uri(
    f"postgresql+psycopg2://{username}:{password}@{host}:{port}/{database}"
)

# Setup llm
llm = OpenAI(temperature=0, openai_api_key=os.environ["OPENAI_API_KEY"])

# Define table_info and few_shot_examples
table_info = """public.songs (
    id  integer,
    year integer,
    position integer,
    song text,
    artist text,
    chart_date date
)"""

few_shot_examples = """
- Question: "Who topped the charts in 2018?"
  SQLQuery: SELECT artist, song FROM songs WHERE year = 2018 AND position = 1;

- Question: "Which artist has the most songs that have made it to the top 20 holiday songs list?"
  SQLQuery: SELECT artist, COUNT(*) AS song_count FROM holiday_songs GROUP BY artist ORDER BY song_count DESC LIMIT 1;

- Question: "What is the highest chart position that a holiday song has achieved each year?"
  SQLQuery: SELECT year, MIN(position) AS highest_position FROM holiday_songs GROUP BY year;

- Question: "How many unique songs have charted in the top 20 over the years?"
  SQLQuery: SELECT COUNT(DISTINCT song) FROM holiday_songs;

- Question: "Which song has appeared most frequently in the top 20 holiday songs list?"
  SQLQuery: SELECT song, COUNT(*) AS appearance_count FROM holiday_songs GROUP BY song ORDER BY appearance_count DESC LIMIT 1;

- Question: "In which year did we have the most number of unique artists in the top 20 holiday songs list?"
  SQLQuery: SELECT year, COUNT(DISTINCT artist) AS unique_artists FROM holiday_songs GROUP BY year ORDER BY unique_artists DESC LIMIT 1;
"""

# Define Custom Prompt
TEMPLATE = """Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Use the following format:

Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"

Only use the following tables:

{table_info}

Some examples of SQL queries that correspond to questions are:

{few_shot_examples}

Question: {input}"""

CUSTOM_PROMPT = PromptTemplate(
    input_variables=["input", "few_shot_examples", "table_info", "dialect"], template=TEMPLATE
)

# Setup the database chain
db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True)

def get_prompt():
    print("Type 'exit' to quit")
    while True:
        prompt = input("Ask a question or type exit to quit: ")

        if prompt.lower() == 'exit':
            print('Exiting...')
            break
        else:
            try:
                question = CUSTOM_PROMPT.format(
                    input=prompt,
                    few_shot_examples=few_shot_examples,
                    table_info=table_info,
                    dialect="PostgreSQL"
                )
                print(db_chain.run(question))
            except Exception as e:
                print(e)

get_prompt()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the application
&lt;/h2&gt;

&lt;p&gt;Run the application using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, ask your &lt;code&gt;holiday_songs&lt;/code&gt; database a question like, "Which topped the charts in 2016?" or "Who had the most number 1’s?".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7S7V_sBg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xvpibsg2njsj540pin0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7S7V_sBg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xvpibsg2njsj540pin0q.png" alt="Image description" width="800" height="848"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it! I hope you enjoy chatting with your holiday song database. Have a great holiday and best wishes in the New Year! 🔔&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://neon.tech/"&gt;Neon Serverless Postgres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.langchain.com/"&gt;LangChain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python.langchain.com/docs/use_cases/qa_structured/sql#case-2-text-to-sql-query-and-execution"&gt;SQLDatabaseChain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kaggle.com/datasets/thedevastator/top-20-holiday-songs-by-position"&gt;Kaggle: Top Holiday Songs by Position Over The Years&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>postgressql</category>
      <category>langchain</category>
      <category>openai</category>
      <category>database</category>
    </item>
  </channel>
</rss>
