Providing efficient and informative customer support is crucial for any financial institution. A well-designed FAQ chat agent can significantly enhance the user experience by offering instant answers to common queries. This article provides a comprehensive guide to building a personalized bank FAQ chat agent using React.js for the frontend, Retrieval-Augmented Generation (RAG) and a Large Language Model (LLM) for intelligent responses, and Redis for robust session management and personalized chat history.
I. The Power of Intelligent Chat for Bank FAQs
Traditional FAQ pages can be cumbersome. An intelligent chat agent offers a more interactive and efficient way to find answers by understanding natural language queries and providing contextually relevant information drawn from the bank’s knowledge base. Leveraging Redis for session management allows for personalized interactions by remembering past conversations within a session.
II. Core Components
- Frontend (React.js): User interface for interaction.
- Backend (Python with Flask): Orchestrates RAG, LLM, and session/chat history (Redis).
- Knowledge Source: Bank’s FAQ documents, policies, website content.
- Embedding Model: Converts text to vectors (e.g., OpenAI Embeddings).
- Vector Database: Stores and indexes vector embeddings (e.g., ChromaDB).
- Large Language Model (LLM): Generates responses (e.g., OpenAI’s GPT models).
- Redis: In-memory data store for sessions and chat history.
- Flask-Session: Flask extension for Redis-backed session management.
- LangChain: Framework for streamlining RAG and LLM interactions.
III. Backend Implementation (Python with Flask, Redis, and RAG)
Python
from flask import Flask, request, jsonify, session
from flask_session import Session
from redis import Redis
import uuid
import json
from flask_cors import CORS
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
from langchain.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os
# --- Configuration ---
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_DB = 0
VECTOR_DB_PATH = "./bank_faq_db"
FAQ_DOCS_PATH = "./bank_faq_docs"
app = Flask(__name__)
CORS(app)
app.config["SESSION_TYPE"] = "redis"
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_REDIS"] = Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
app.secret_key = "your_bank_faq_secret_key" # Replace with a strong key
sess = Session(app)
# --- Initialize RAG Components ---
embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)
if not os.path.exists(VECTOR_DB_PATH):
# --- Data Ingestion (Run once to create the vector database) ---
if not os.path.exists(FAQ_DOCS_PATH):
os.makedirs(FAQ_DOCS_PATH)
print(f"Please place your bank's FAQ documents (e.g., .txt files) in '{FAQ_DOCS_PATH}' and rerun the backend to process them.")
vectordb = None
else:
loader = DirectoryLoader(FAQ_DOCS_PATH, glob="**/*.txt", loader_cls=TextLoader)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = text_splitter.split_documents(documents)
vectordb = Chroma.from_documents(chunks, embeddings, persist_directory=VECTOR_DB_PATH)
vectordb.persist()
else:
vectordb = Chroma(persist_directory=VECTOR_DB_PATH, embedding_function=embeddings)
qa_chain = RetrievalQA.from_chain_type(llm=OpenAI(openai_api_key=OPENAI_API_KEY), chain_type="stuff", retriever=vectordb.as_retriever() if vectordb else None)
# --- Redis Helper Functions ---
def store_message(session_id, sender, text):
redis_client = app.config["SESSION_REDIS"]
key = f"bank_faq_chat:{session_id}"
message = {"sender": sender, "text": text}
redis_client.rpush(key, json.dumps(message))
def get_history(session_id):
redis_client = app.config["SESSION_REDIS"]
key = f"bank_faq_chat:{session_id}"
history_bytes = redis_client.lrange(key, 0, -1)
return [json.loads(hb.decode('utf-8')) for hb in history_bytes]
# --- API Endpoints ---
@app.route('/create_session')
def create_session():
if 'bank_faq_session_id' not in session:
session_id = str(uuid.uuid4())
session['bank_faq_session_id'] = session_id
return jsonify({"session_id": session_id})
else:
return jsonify({"session_id": session['bank_faq_session_id']})
@app.route('/get_chat_history')
def get_chat_history():
if 'bank_faq_session_id' not in session:
return jsonify({"history": []})
session_id = session['bank_faq_session_id']
history = get_history(session_id)
return jsonify({"history": history})
@app.route('/bank_faq/chat', methods=['POST'])
def bank_faq_chat():
if 'bank_faq_session_id' not in session:
return jsonify({"error": "No active session."}), 401
session_id = session['bank_faq_session_id']
data = request.get_json()
user_message = data.get('message')
if not user_message:
return jsonify({"error": "Message is required"}), 400
store_message(session_id, "user", user_message)
try:
if qa_chain:
response = qa_chain.run(user_message)
store_message(session_id, "agent", response)
return jsonify({"response": response})
else:
error_message = "Bank FAQ knowledge base not initialized. Please ensure FAQ documents are present and the backend is run to process them."
store_message(session_id, "agent", error_message)
return jsonify({"error": error_message}), 500
except Exception as e:
error_message = f"Sorry, I encountered an error: {str(e)}"
store_message(session_id, "agent", error_message)
return jsonify({"error": error_message}), 500
if __name__ == '__main__':
print("Make sure you have your OpenAI API key set as an environment variable (OPENAI_API_KEY).")
print(f"Place bank FAQ documents in '{FAQ_DOCS_PATH}' for processing.")
app.run(debug=True)
IV. Frontend Implementation (React.js)
JavaScript
import React, { useState, useEffect, useRef } from 'react';
function BankFAQChat() {
const [messages, setMessages] = useState([]);
const [inputValue, setInputValue] = useState('');
const [isLoading, setIsLoading] = useState(false);
const chatWindowRef = useRef(null);
const [sessionId, setSessionId] = useState(null);
useEffect(() => {
const fetchSessionAndHistory = async () => {
try {
const sessionResponse = await fetch('/create_session');
if (sessionResponse.ok) {
const sessionData = await sessionResponse.json();
setSessionId(sessionData.session_id);
if (sessionData.session_id) {
const historyResponse = await fetch('/get_chat_history');
if (historyResponse.ok) {
const historyData = await historyResponse.json();
setMessages(historyData.history);
} else {
console.error('Failed to fetch chat history:', historyResponse.status);
}
}
} else {
console.error('Failed to create/retrieve session:', sessionResponse.status);
}
} catch (error) {
console.error('Error fetching session and history:', error);
}
};
fetchSessionAndHistory();
}, []);
useEffect(() => {
if (chatWindowRef.current) {
chatWindowRef.current.scrollTop = chatWindowRef.current.scrollHeight;
}
}, [messages]);
const sendMessage = async () => {
if (inputValue.trim() && sessionId) {
const newMessage = { sender: 'user', text: inputValue };
setMessages([...messages, newMessage]);
setInputValue('');
setIsLoading(true);
try {
const response = await fetch('/bank_faq/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: inputValue }),
});
if (response.ok) {
const data = await response.json();
const agentMessage = { sender: 'agent', text: data.response };
setMessages([...messages, newMessage, agentMessage]);
} else {
console.error('Error sending message:', response.status);
const errorMessage = { sender: 'agent', text: 'Sorry, I encountered an error.' };
setMessages([...messages, newMessage, errorMessage]);
}
} catch (error) {
console.error('Error sending message:', error);
const errorMessage = { sender: 'agent', text: 'Sorry, I encountered an error.' };
} finally {
setIsLoading(false);
}
}
};
return (
<div className="chat-container" style={styles.chatContainer}>
<div ref={chatWindowRef} className="message-list" style={styles.messageList}>
{messages.map((msg, index) => (
<div key={index} className={`message ${msg.sender}`} style={msg.sender === 'user' ? styles.userMessage : styles.agentMessage}>
{msg.text}
</div>
))}
{isLoading && <div className="message agent" style={styles.agentMessage}>Thinking...</div>}
</div>
<div className="input-area" style={styles.inputArea}>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(event) => event.key === 'Enter' && sendMessage()}
placeholder="Ask a bank FAQ..."
style={styles.input}
/>
<button onClick={sendMessage} disabled={isLoading} style={styles.button}>Send</button>
</div>
</div>
);
}
const styles = {
chatContainer: { width: '400px', margin: '20px auto', border: '1px solid #ccc', borderRadius: '5px', overflow: 'hidden', display: 'flex', flexDirection: 'column' },
messageList: { flexGrow: 1, padding: '10px', overflowY: 'auto' },
userMessage: { backgroundColor: '#e0f7fa', padding: '8px', borderRadius: '5px', marginBottom: '5px', alignSelf: 'flex-end', maxWidth: '70%', wordBreak: 'break-word' },
agentMessage: { backgroundColor: '#f5f5f5', padding: '8px', borderRadius: '5px', marginBottom: '5px', alignSelf: 'flex-start', maxWidth: '70%', wordBreak: 'break-word' },
inputArea: { padding: '10px', borderTop: '1px solid #eee', display: 'flex' },
input: { flexGrow: 1, padding: '8px', borderRadius: '3px', border: '1px solid #ddd', marginRight: '10px' },
button: { padding: '8px 15px', borderRadius: '3px', border: 'none', backgroundColor: '#00bcd4', color: 'white', cursor: 'pointer', fontWeight: 'bold', '&:disabled': { backgroundColor: '#ccc', cursor: 'not-allowed' } },
};
export default BankFAQChat;
V. Running the Application
- Install Backend Dependencies:
pip install Flask flask-session redis flask-cors langchain openai chromadb
- Set Up OpenAI API Key: Ensure you have an OpenAI API key and set it as an environment variable named
OPENAI_API_KEY
. - Prepare Bank FAQ Documents: Create a directory
./bank_faq_docs
and place your bank’s FAQ documents (as.txt
files) inside. - Run Backend (Initial Data Ingestion): Run the backend script once. It will attempt to create the vector database if it doesn’t exist. Ensure your FAQ documents are in the specified directory.
- Ensure Redis is Running: Start your Redis server.
- Run the Backend: Execute the backend script.
- Running the React Frontend
- Here are the instructions to get the React frontend of the Bank FAQ Chat Agent running:
- Navigate to your React project directory in your terminal. If you haven’t created a React project yet, you can do so using Create React App or a similar tool: Bash
npx create-react-app bank-faq-frontend cd bank-faq-frontend
- Install Dependencies: If you started with a fresh React project, you’ll need to install any necessary dependencies (though this example uses built-in React features like
useState
anduseEffect
). If you have a pre-existing project, ensure you havereact
andreact-dom
installed. Bashnpm install # Or yarn install
- Replace
src/App.js
(or your main component file): Open thesrc/App.js
file (or the main component where you want to place the chat agent) and replace its entire content with the React code provided in the previous section. You might need to adjust the import path if your component is named differently or located in a different directory. For example, if you save the code in a file namedBankFAQChat.js
within acomponents
folder, you would import it inApp.js
like this: JavaScriptimport BankFAQChat from './components/BankFAQChat'; function App() { return ( <div> <BankFAQChat /> </div> ); } export default App;
- Start the Development Server: Run the React development server from your terminal within the React project directory: Bash
npm start # Or yarn start
This command will typically open your React application in a new tab in your web browser, usually athttp://localhost:3000
. - Interact with the Chat Agent: Once the frontend is running, you should see the chat interface. You can type your bank-related questions in the input field and click the “Send” button (or press Enter) to send them to the backend. The agent’s responses and the conversation history will be displayed in the chat window.
- Important Notes for the Frontend:
- Backend URL: Ensure that the
fetch
calls in theBankFAQChat
component (/create_session
and/bank_faq/chat
) are pointing to the correct URL where your Flask backend is running. If your backend is running on a different host or port thanhttp://localhost:5000
, you’ll need to update these URLs accordingly. - Styling: The provided
styles
object in the React component offers basic styling. You can customize this further or use a CSS-in-JS library (like Styled Components) or a CSS framework (like Tailwind CSS or Material UI) to enhance the visual appearance of the chat agent. - Error Handling: The frontend includes basic
console.error
logging for API request failures. You might want to implement more user-friendly error messages within the UI. - Session Management: The frontend automatically fetches or creates a session on mount. The
sessionId
is managed in the component’s state. - Create React App: Create a new React application if you haven’t already.
- Replace Frontend Code: Replace the content of your main React component file with the provided
BankFAQChat
component code. - Start Frontend: Run your React development server. For Detail see below
Running the React Frontend
Here are the instructions to get the React frontend of the Bank FAQ Chat Agent running:
Navigate to your React project directory in your terminal. If you haven’t created a React project yet, you can do so using Create React App or a similar tool:
Bash
npx create-react-app bank-faq-frontend
cd bank-faq-frontend
Install Dependencies: If you started with a fresh React project, you’ll need to install any necessary dependencies (though this example uses built-in React features like useState and useEffect). If you have a pre-existing project, ensure you have react and react-dom installed.
Bash
npm install # Or yarn install
Replace src/App.js (or your main component file): Open the src/App.js file (or the main component where you want to place the chat agent) and replace its entire content with the React code provided in the previous section. You might need to adjust the import path if your component is named differently or located in a different directory. For example, if you save the code in a file named BankFAQChat.js within a components folder, you would import it in App.js like this:
JavaScript
import BankFAQChat from ‘./components/BankFAQChat’;
function App() {
return (
<div>
<BankFAQChat />
</div>
);
}
export default App;
Start the Development Server: Run the React development server from your terminal within the React project directory:
Bash
npm start # Or yarn start
This command will typically open your React application in a new tab in your web browser, usually at http://localhost:3000.
Interact with the Chat Agent: Once the frontend is running, you should see the chat interface. You can type your bank-related questions in the input field and click the “Send” button (or press Enter) to send them to the backend. The agent’s responses and the conversation history will be displayed in the chat window.
Important Notes for the Frontend:
Backend URL: Ensure that the fetch calls in the BankFAQChat component (/create_session and /bank_faq/chat) are pointing to the correct URL where your Flask backend is running. If your backend is running on a different host or port than http://localhost:5000, you’ll need to update these URLs accordingly.
Styling: The provided styles object in the React component offers basic styling. You can customize this further or use a CSS-in-JS library (like Styled Components) or a CSS framework (like Tailwind CSS or Material UI) to enhance the visual appearance of the chat agent.
Error Handling: The frontend includes basic console.error logging for API request failures. You might want to implement more user-friendly error messages within the UI.
Session Management: The frontend automatically fetches or creates a session on mount. The sessionId is managed in the component’s state.
By following these instructions, you should be able to run the React frontend and interact with the Bank FAQ Chat Agent, provided that your Flask backend is also running and correctly configured.
This setup provides a functional bank FAQ chat agent with personalized history within a session, powered by RAG and an LLM. Remember to replace placeholders and configure API keys and file paths according to your specific environment and data.