JoluMate is an AI chatbot application designed for interactive
conversations, secure user authentication, and intelligent
responses powered by Retrieval Augmented Generation (RAG). Users
can manage their chat history, engage with the AI assistant, and
upload PDF documents to provide custom knowledge for
context-aware interactions.
- ✨ Key Features
- 🛠️ Tech Stack
- 📂 Folder Structure
- ⚙️ Installation
- 🚀 Usage
- 🌐 Configuration / Environment Variables
- 🧠 How the Code Works
- 📞 API Endpoints
- ⚖️ License
- User Authentication: Robust signup, login, logout, and
token refresh mechanisms using JWT for secure access. - Chatbot Interaction: Engage in natural language conversations with an AI assistant powered by a Groq LLM.
- Conversation Management: View, load, and delete individual chat conversations, maintaining chat history.
- Document Upload: Upload PDF files which are processed,
chunked, embedded, and stored to augment the AI's knowledge base. - Retrieval Augmented Generation (RAG): The AI agent
leverages uploaded documents to provide contextually relevant and informed responses. - LangGraph Workflow: An asynchronous LangGraph
orchestrates the AI agent's decision-making, tool usage (like
knowledge base search), and state management. - Persistent Data Storage: User credentials, refresh
tokens, conversation history, and document embeddings are
securely stored in a PostgreSQL database. - Web Interface: A Streamlit-based client provides an
intuitive and interactive user interface for accessing chatbot
functionalities. - Request Logging: Server-side middleware logs incoming
HTTP requests for monitoring and debugging.
- Backend Framework: FastAPI
- Client Framework: Streamlit
- Database: PostgreSQL
- Asynchronous Database Driver:
psycopg_pool,psycopg - AI Frameworks: LangChain, LangGraph
- LLM Provider: Groq
- LLM Model:
llama-3.3-70b-versatile - Embedding Model: Google Generative AI
(
models/text-embedding-004) - Authentication: JWT (JSON Web Tokens),
passlib(bcrypt) - HTTP Client:
requests - PDF Processing:
pypdf - Environment Variables:
python-dotenv - Data Validation: Pydantic
- Web Server: Uvicorn (implied with FastAPI)
- Concurrency:
asyncio
JoluMate/
├── LICENSE
└── README.md
├── client/
├── api.py
├── app.py
├── db/
└── formatting.sql
├── server/
├── main.py
├── agent/
└── graph.py
├── auth/
├── auth.py
├── hash.py
└── router.py
├── chat/
└── router.py
├── configs/
└── db.py
├── conversation/
└── router.py
├── middlewares/
└── log_requests.py
├── rag/
├── tools.py
└── utils.py
To set up and run JoluMate locally, follow these steps:
- Python 3.9+
- PostgreSQL database
git
git clone <repository_url>
cd JoluMateCreate a .env file in the root JoluMate/ directory and
populate it with the necessary environment variables.
# Client-side
BACKEND_URL="http://localhost:8000" # Or your deployed backend
URL
# Server-side
GROQ_API_KEY="your_groq_api_key_here"
JWT_SECRET="super_secret_jwt_key" # Change this to a strong,
random key
DATABASE_URL="postgresql://user:password@host:port/database_name"
GOOGLE_API_KEY="your_google_api_key_here"It is recommended to use a virtual environment.
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
pip install -r requirements.txtrequirements.txt content (based on file summaries):
fastapi
streamlit
requests
python-dotenv
uvicorn
psycopg-pool
psycopg # Or psycopg if you prefer source build
langchain-groq
langchain-core
langgraph
python-jose
passlib
pydantic
pypdf
langchain-text-splitters
langchain-google-genai
Ensure you have a PostgreSQL database running. Then, apply the
schema using the provided SQL script:
psql -U your_username -d your_database_name -f db/formatting.sql Replace your_username and your_database_name with your
PostgreSQL credentials.
Navigate to the server/ directory and start the FastAPI
application:
cd server
uvicorn main:app --reloadThe server will typically run on http://localhost:8000.
Open a new terminal, activate your virtual environment, navigate
to the client/ directory, and start the Streamlit application:
cd client
streamlit run app.pyThe Streamlit app will open in your web browser, usually at
http://localhost:8501.
Once both the backend and client applications are running:
- Access the Streamlit UI: Open your web browser to
http://localhost:8501. - Sign Up / Log In: Use the Login or Signup tabs to create a new account or log in with existing credentials.
- Chat with JoluMate: After logging in, you can start new
conversations, send messages, and view chat history in the main
panel. - Upload Documents: Use the "Upload PDF" feature in the
sidebar to add PDF documents. The AI agent will then be able to
retrieve information from these documents to answer your questions. - Manage Conversations: In the sidebar, you can select
existing conversations to continue them or delete them as needed.
The application's behavior is influenced by several environment
variables and constants:
Loaded from .env files:
BACKEND_URL: (Client-side) The base URL for the backend
API.GROQ_API_KEY: (Server-side) API key required for accessing the Groq LLM.JWT_SECRET: (Server-side) Secret key used for signing and
verifying JSON Web Tokens.DATABASE_URL: (Server-side) Connection string for the
PostgreSQL database.GOOGLE_API_KEY: (Server-side) API key for accessing Google Generative AI embedding models.
Configured within the server code:
ACCESS_TOKEN_MINUTES: Lifetime duration for JWT access
tokens (in minutes). Defined inserver/auth/auth.py.REFRESH_TOKEN_DAYS: Lifetime duration for refresh tokens
(in days). Defined inserver/auth/auth.py.EMBEDDINGS_MODEL: Specifiesmodels/text-embedding-004as the embedding model for Google Generative AI. Defined inserver/rag/utils.py.CHUNK_SIZE: The maximum character size for text chunks
during document processing (default: 1000 characters). Defined inserver/rag/utils.py.CHUNK_OVERLAP: The character overlap between consecutive
text chunks during document processing (default: 200 characters). Defined inserver/rag/utils.py.DEFAULT_SEARCH_LIMIT: The default limit for the number of
document search results to retrieve (default: 5 documents).
Defined inserver/rag/utils.py.DATABASE_POOL_SETTINGS: Configured inserver/configs/db.pyforpsycopg_pool, includingmin_size=1,max_size=10,row_factory=dict_row,autocommit=True, andprepare_threshold=None.
JoluMate is structured as a client-server application, with a
Streamlit frontend interacting with a FastAPI backend.
-
Client Application (
client/app.py&client/api.py):- The
client/app.pyfile powers the Streamlit web
interface, providing the UI for user authentication, conversation display, PDF uploads, and chat input. It manages the application's session state, including user information, active
conversation IDs, and chat messages. client/api.pyacts as a thin client-side wrapper,
encapsulating HTTP requests to the backend API. It defines helper functions for signup, login, logout, fetching user info, getting answers, retrieving chat history, listing conversations, deleting conversations, and uploading documents. It loadsBACKEND_URL
from the.envfile.
- The
-
Backend Application (
server/main.py):server/main.pyis the entry point for the FastAPI
server. It configures the FastAPI application, sets up an
asynchronous PostgreSQL connection pool (configs.db.pool), and initializes the LangGraph checkpointer (agent.graph.checkpointer) during its lifespan for persistent
state management.- It registers a custom
log_requestsmiddleware (middlewares/log_requests.py) to log all incoming HTTP requests. - It includes routers for authentication
(
auth/router.py), chat interactions (chat/router.py), and
conversation management (conversation/router.py).
-
Database Management (
db/formatting.sql&server/configs/db.py):db/formatting.sqldefines the PostgreSQL database
schema. It creates tables forusers(credentials),refresh_tokens(JWT refresh tokens),conversations(chat
metadata),chats(individual messages), anddocuments
(uploaded PDF text chunks with vector embeddings). It also sets
upvectorandpgcryptoextensions.server/configs/db.pyestablishes an asynchronous
PostgreSQL connection pool usingpsycopg_pool, configured to
handle database connections efficiently and provide them via theget_connasync generator. It loads theDATABASE_URLfrom the environment.
-
Authentication (
server/auth/):server/auth/hash.pyprovides utilities for securely
hashing user passwords usingbcrypt(viapasslib) and
verifying them against stored hashes.server/auth/auth.pyhandles the core JWT logic. It
creates access tokens (containinguser_id) and random refresh
tokens, manages their expiry, and stores refresh tokens in the
database. It also definesget_useras a FastAPI dependency to
authenticate requests by validating access tokens from cookies
and retrieving user details.server/auth/router.pydefines API endpoints for user
authentication. This includes/auth/signup(creates new users),/auth/login(verifies credentials, issues JWTs, sets HttpOnly
cookies),/auth/refresh(rotates refresh tokens),/auth/logout(clears tokens and cookies), and/auth/me
(retrieves current user profile).
-
Chat and Conversation Management (
server/chat/router.py&server/conversation/router.py):server/chat/router.pymanages all chat-related API
interactions under the/chatprefix. It handlesPOST /chat/askrequests by saving user messages, invoking the AI
agent (agent.graph.workflow) to generate responses, and storing assistant replies. It dynamically creates new conversations if noconversation_idis provided. It also providesGET /chat/{conversation_id}for retrieving chat history.server/conversation/router.pyprovides API endpoints
for managing conversations under the/conversationsprefix. It offersGET /conversationsto list all conversations for an
authenticated user andPOST /conversations/deleteto remove a
specific conversation and all its associated chat messages from
the database.
-
AI Agent (
server/agent/graph.py):server/agent/graph.pydefines the core AI agent using
LangGraph. It establishes an asynchronous workflow named "JoluMate" using aChatGroqLLM (specificallyllama-3.3-70b-versatile).- The agent uses a
search_knowledge_basetool (rag.tools.search_knowledge_base) to query uploaded documents. - The LangGraph workflow is built with an
agent_node(for LLM invocation with a system prompt) and aToolNode(for
executing tools). Conditional routing ensures the graph transitions to thetoolsnode when the LLM decides to use a
tool, otherwise, it proceeds with direct LLM responses. - The agent's state is persistently stored using an
AsyncPostgresSavercheckpoint, allowing conversations to resume seamlessly.
-
Retrieval Augmented Generation (RAG) (
server/rag/):server/rag/utils.pycontains the core logic for PDF
processing and vector search. It extracts text from PDF files
usingpypdf, splits the text into overlapping chunks using
RecursiveCharacterTextSplitter, generates vector embeddings for each chunk usingGoogleGenerativeAIEmbeddings(withmodels/text-embedding-004), and stores these in thedocumentstable. It also provides thesearch_documentsfunction, which
performs a cosine similarity search on stored embeddings in
PostgreSQL to retrieve relevant document content for a given
query and user.server/rag/tools.pydefines thesearch_knowledge_baseasynchronous LangChain tool. This tool acts as the interface for the AI agent to interact with the RAG system. It receives a user query, extracts theuser_idfrom the LangGraphRunnableConfig, and then callsrag.utils.search_documentsto fetch relevant information from the user's uploaded documents,
returning the results to the AI agent.
The JoluMate backend provides the following REST API endpoints:
POST /auth/signup- Description: Registers a new user.
- Request Body:
{"name": "...", "email": "...", "password": "..."} - Success Response:
{"message": "User created successfully"}(Status: 201)
POST /auth/login- Description: Authenticates a user, issues access and refresh tokens, and sets them as HttpOnly cookies.
- Request Body:
{"email": "...", "password": "..."} - Success Response:
{"access_token": "..."}(Status:
POST /auth/refresh- Description: Validates the refresh token (from
cookie), issues new access and refresh tokens, and updates
HttpOnly cookies. - Success Response:
{"access_token": "..."}(Status:
- Description: Validates the refresh token (from
POST /auth/logout- Description: Deletes the refresh token from the
database and clears authentication cookies. - Success Response:
{"message": "Logged out successfully"}(Status: 200)
- Description: Deletes the refresh token from the
GET /auth/me- Description: Retrieves the details of the currently
authenticated user. - Success Response:
{"id": "...", "name": "...", "email": "..."}(Status: 200)
- Description: Retrieves the details of the currently
POST /chat/ask- Description: Submits a user message to the AI agent
and retrieves an AI-generated response. Creates a new conversation ifconversation_idis not provided. - Request Body:
{"message": "user's question", "conversation_id": "optional_conversation_id"} - Success Response:
{"conversation_id": "...", "answer": "AI's response"}(Status: 200)
- Description: Submits a user message to the AI agent
GET /chat/{conversation_id}- Description: Fetches all chat messages for a specific conversation, ordered by creation time.
- Path Parameter:
conversation_id(UUID string) - Success Response:
[{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}, ...](Status:
POST /chat/upload- Description: Uploads a PDF file for processing and
integration into the RAG knowledge base. - Request Body: Form data with
filefield containing the PDF file. - Success Response:
{"message": "File uploaded and processed successfully"}(Status: 200)
- Description: Uploads a PDF file for processing and
GET /conversations- Description: Lists all conversations belonging to the authenticated user, ordered by creation date (descending).
- Success Response:
[{"id": "...", "title": "...", "created_at": "..."}, ...](Status: 200)
POST /conversations/delete- Description: Deletes a specific conversation and all
its associated chat messages if it belongs to the authenticated
user. - Query Parameter:
conversation_id(UUID string) - Success Response:
{"message": "Conversation deleted successfully"}(Status: 200)
- Description: Deletes a specific conversation and all
its associated chat messages if it belongs to the authenticated
GET /- Description: A simple health check endpoint.
- Success Response:
{"message": "Hello JoluMate!"}
(Status: 200)
This project is licensed under the MIT License.
Copyright (c) 2025 Sarowar Jahan Biswas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.