0% found this document useful (0 votes)
10 views5 pages

SQL Chatbot with Ollama LLM Integration

The document outlines a Python script for a SQL chatbot that utilizes the Langchain library, Ollama LLM, and SQLAlchemy to interact with an Oracle database. It includes functionalities for processing user queries, converting names to emails, and generating SQL queries based on user input. The chatbot is designed to provide natural language responses derived from SQL query results while maintaining a conversational history.

Uploaded by

hemsbabu.km
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views5 pages

SQL Chatbot with Ollama LLM Integration

The document outlines a Python script for a SQL chatbot that utilizes the Langchain library, Ollama LLM, and SQLAlchemy to interact with an Oracle database. It includes functionalities for processing user queries, converting names to emails, and generating SQL queries based on user input. The chatbot is designed to provide natural language responses derived from SQL query results while maintaining a conversational history.

Uploaded by

hemsbabu.km
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

# Credits for Original script with streamlit and hugginface

# [Link]

import logging
import warnings
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.utilities import SQLDatabase
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from [Link] import create_engine
from [Link] import LLM
from typing import Optional, List
import spacy
import ollama
from sqlalchemy import exc

[Link]("ignore", category=[Link])
# Set up logging
#[Link](level=[Link])

username = 'hr'
password = 'hr'
host = 'localhost'
port = '1521' # Default Oracle port
service_name = 'FREE'

# Create the DSN (Data Source Name)


#dsn = f"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={host})(PORT={port}))
(CONNECT_DATA=(SERVICE_NAME={service_name})))"

# Create the SQLAlchemy engine


engine = create_engine(f"oracle+cx_oracle://{username}:{password}@{service_name}")

# Custom Ollama LLM class that uses the ollama library


class OllamaLLM(LLM):
model_name: str = "llama3.2:3b"

def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:


#[Link](f"LLM Prompt: {prompt}")
response = [Link](model=self.model_name, messages=[
{
'role': 'user',
'content': prompt,
},
])
#[Link](f"LLM Response: {response}")
return response['message']['content']

@property
def _identifying_params(self):
return {"model_name": self.model_name}

@property
def _llm_type(self) -> str:
return "ollama"

# Initialize the custom Ollama LLM


llm = OllamaLLM()

# Create SQLDatabase instance


db = SQLDatabase(engine)

# Load Spacy model


nlp = [Link]("en_core_web_md")

def get_sql_chain(db):
template = """
You are an expert oracle database data analyst at a company. You are
interacting with a user who is asking you questions about the our employees.

Here is the schema of the hr employees table

Name Null? Type


----------------------------------------- -------- ----------------------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)

Write only the SQL query and nothing else.

Do not wrap the SQL query in any other text, not even backticks.

For example:

Question: How many users?


SQL Query: SELECT count(*) from employees

Question: list all users with names starting with A


SQL Query: SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEES WHERE FIRST_NAME LIKE
'A%%' ORDER BY FIRST_NAME ASC

** Notice there is not semicolun at the end of the statement **

.......

Conversation History:
{chat_history}

Question: {question}
SQL Query:
"""
prompt = ChatPromptTemplate.from_template(template)

def get_schema(_):
schema = db.get_table_info()
#[Link](f"Database Schema: {schema}")
return schema

return (
[Link](schema=get_schema)
| prompt
| llm
| StrOutputParser()
)

def convert_name_to_email(name):
# Split the name by space
parts = [Link]()
# Check if the name contains two parts
if len(parts) == 2:
first_name, last_name = parts
# Construct the email address
email = f"{first_name.lower()}.{last_name.lower()}@[Link]"
#[Link](f"Converted name '{name}' to email '{email}'")
return email
return None

def format_chat_history(chat_history):
formatted_history = ""
for message in chat_history:
if isinstance(message, HumanMessage):
formatted_history += f"User: {[Link]}\n"
elif isinstance(message, AIMessage):
formatted_history += f"Assistant: {[Link]}\n"
return formatted_history.strip()

def get_response(user_query: str, db: SQLDatabase, chat_history: list):


#[Link](f"User Query: {user_query}")
# Handle greetings separately
greetings = ["hi", "hello", "hola", "good morning", "good afternoon", "good
evening", "good night"]
if user_query.lower() in greetings:
return "Hello! How can I assist you today?"

# Handle conversation separately


conversations = ["ok", "thank you", "see you", "nice", "great"]
if user_query.lower() in conversations:
return "Can I help you with anything else?"

# Handle goodbye separately


goodbyes = ["goodbye", "bye", "ok bye"]
if user_query.lower() in goodbyes:
return "Goodbye!"

# Process user query with Spacy to handle similar questions


doc = nlp(user_query)
entities = [([Link], ent.label_) for ent in [Link]]
#[Link](f"Extracted Entities: {entities}")

# Check for user names in the entities


for text, label in entities:
if label == "PERSON":
email = convert_name_to_email(text)
if email:
user_query = user_query.replace(text, email)
#[Link](f"User query after name to email conversion:
{user_query}")

# Process the modified user query


sql_chain = get_sql_chain(db)

template = """
You are a data analyst at a company. You are interacting with a user who is asking
you questions about the company's database.
Based on the table schema below, question, SQL query, and SQL response, provide a
natural language response.

Use the SQL Response to give the answer. Convert the SQL response into natural
language before presenting it. Do not print the SQL response in the output; only
provide the natural language response.

If the SQL Response is a count (e.g., COUNT(*)), the natural language output should
clearly and accurately state the count.

If the SQL response contains a single value (e.g., COUNT(*)), extract and use this
value directly in the natural language response.

If there is no data available for any SQL query, then output "Data not found".

Do not print outputs in paragraph format. Do not print Conversation history in


output; only print the final output that is converted to natural language from the
SQL response.

Do not print extra information; only give the required information to the user.

Provide all natural language outputs in numbered or bullet list format.

<SCHEMA>
{schema}
</SCHEMA>

Question: {question}
SQL Query: <SQL>{query}</SQL>
SQL Response: {response}
"""
prompt = ChatPromptTemplate.from_template(template)

chain = (
[Link](query=sql_chain).assign(
schema=lambda _: db.get_table_info(),
response=lambda vars: [Link](vars["query"]),
)
| prompt
| llm
| StrOutputParser()
)

# Prepare variables for the chain


formatted_history = format_chat_history(chat_history)
variables = {
"question": user_query,
"chat_history": formatted_history,
}
#[Link](f"Chain Variables: {variables}")

# Invoke the chain


try:
result = [Link](variables)
#[Link](f"Chain Result: {result}")
except Exception as e:
#[Link](f"Error during chain invocation: {e}")
result = "Sorry, an error occurred while processing your request."

# Remove any leading/trailing whitespace and unnecessary prefixes


result = [Link]()
# If the result starts with "Bot:" or "Assistant:", remove it
if [Link]("Bot:"):
result = result[len("Bot:"):].strip()
if [Link]("Assistant:"):
result = result[len("Assistant:"):].strip()

return result

def main():
chat_history = [
AIMessage(content="Hello! I'm a SQL Chatbot. Ask me anything about the
database."),
]
print("Bot: Hello! I'm a Oracle Database Chatbot. Ask me anything about the
database.")
db = SQLDatabase(engine)

while True:
user_query = input("You: ")
if user_query.lower().strip() in ['exit', 'quit', 'bye']:
print("Bot: Goodbye!")
break
if user_query.strip() == "":
continue
chat_history.append(HumanMessage(content=user_query))
response = get_response(user_query, db, chat_history)
print(f"Bot: {response}")
chat_history.append(AIMessage(content=response))

if __name__ == "__main__":
main()

Common questions

Powered by AI

The system differentiates user inputs by using different processing techniques. For names, it uses Spacy to extract entities like 'PERSON' and convert them to emails for database queries. Greetings, goodbyes, and conversational phrases are matched against predefined lists to trigger specific responses. This layered approach ensures accurate handling of varied user queries .

The user query is processed through a function that uses Spacy to identify entities such as names and convert them to emails. The query is then modified and integrated into a SQL chain using a ChatPromptTemplate. This involves passing through a series of steps including schema fetching, SQL query execution, and utilizing a language model to generate a natural language response based on SQL responses .

The system converts a user's name into an email format by first splitting the name into parts by spaces. If the name contains exactly two parts, representing the first and last names, the email address is constructed by joining them in lowercase with a dot between, followed by '@email.com'. This conversion ensures proper recognition and handling of names within user queries .

Spacy is employed in the system to perform entity recognition on user queries, specifically extracting person names. This functionality helps in transforming real names into email addresses for consistency when interacting with the database. Its integration ensures that user inputs are correctly interpreted and modified before further processing .

The chatbot handles generic conversation elements by matching user queries against predefined lists of greetings, conversational acknowledgements, and goodbyes. If a match is found, it returns a standard response like "Hello! How can I assist you today?" or "Goodbye!" without further processing through the SQL system, which maintains the conversational flow and usability .

The Ollama LLM model is integrated into the SQL chatbot system through a custom class called OllamaLLM which extends the base LLM class. The integration involves defining a `_call` method that sends the prompt to the Ollama library and receives the response. The model is initialized with the name 'llama3.2:3b', and its interaction occurs in a pipeline with other components like ChatPromptTemplate and StrOutputParser to process user queries and convert SQL responses into natural language outputs .

The chatbot incorporates error handling through logging mechanisms and exception management within the transformation chain. If an exception occurs during chain invocation, it returns a user-friendly message like "Sorry, an error occurred while processing your request." Additionally, logging debug statements are used throughout to trace and diagnose potential issues, enhancing system reliability .

Logging configurations help monitor the system's execution by providing insights into operations like LLM prompts, SQL execution, and error management. In the document, logging is omitted in the final setup for clear outputs, but comments indicate its use in development for debugging purposes. It includes debug statements that could assist in tracking the flow of data and pinpointing issues .

The ChatPromptTemplate serves as a structured format that guides the interaction between the chatbot and the user. It ensures that each query is processed in a consistent manner, outlining how the user question, SQL query, and SQL response should be transformed into a natural language output. By defining this workflow, it facilitates clear and accurate communication through the chatbot system .

Creating a SQLAlchemy engine is crucial for establishing a connection between the application and the Oracle database. It provides the necessary interface for executing SQL queries, managing session transactions, and ensuring efficient communication with the database server. This setup allows the chatbot to fetch data and handle user queries effectively .

You might also like