Building a Chat Application with Streamlit, SQLite, and xAI's Grok API
Learn how to create a chat application using Streamlit, SQLite for conversation storage, and xAI's Grok API for AI responses.
Building a Chat Application with Streamlit, SQLite, and xAI's Grok API
This tutorial walks you through creating a chat application using Streamlit, SQLite for conversation storage, and xAI's Grok API for AI responses. The app allows users to start new conversations, view past conversations, and interact with Grok, an AI assistant.
Prerequisites
- Python 3.8+
- Streamlit (
pip install streamlit
) - OpenAI Python client (
pip install openai
) - SQLite (included in Python standard library)
- xAI API key (obtain from xAI)
Project Structure
The application consists of a single Python script that handles:
- Database setup with SQLite
- Conversation management
- API integration with xAI's Grok
- Streamlit UI for chat and conversation navigation
Below is the complete code, followed by a detailed breakdown.
import streamlit as st
from openai import OpenAI
import sqlite3
import uuid
from datetime import datetime
# Database setup
def init_db():
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS conversations
(conversation_id TEXT, timestamp TEXT)
''')
c.execute('''
CREATE TABLE IF NOT EXISTS messages
(id INTEGER PRIMARY KEY, conversation_id TEXT, role TEXT, content TEXT, timestamp TEXT)
''')
conn.commit()
conn.close()
def save_message(conversation_id, role, content):
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
timestamp = datetime.now().isoformat()
c.execute("INSERT INTO messages (conversation_id, role, content, timestamp) VALUES (?, ?, ?, ?)",
(conversation_id, role, content, timestamp))
conn.commit()
conn.close()
def get_conversation_history(conversation_id):
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
c.execute("SELECT role, content FROM messages WHERE conversation_id = ? ORDER BY id", (conversation_id,))
messages = c.fetchall()
conn.close()
return [{"role": role, "content": content} for role, content in messages]
def get_all_conversations():
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
c.execute("SELECT DISTINCT conversation_id, timestamp FROM conversations ORDER BY timestamp DESC")
conversations = c.fetchall()
conn.close()
return conversations
def create_new_conversation():
conversation_id = str(uuid.uuid4())
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
timestamp = datetime.now().isoformat()
c.execute("INSERT INTO conversations (conversation_id, timestamp) VALUES (?, ?)",
(conversation_id, timestamp))
conn.commit()
conn.close()
# Add system message to the new conversation
system_message = "You are Grok, an extremely intelligent developer and entrepreneur. Specializing in various programming languages."
save_message(conversation_id, "system", system_message)
return conversation_id
# Initialize database
init_db()
# Initialize xAI client with hardcoded API key
client = OpenAI(
api_key="you're_api_key_here",
base_url="https://api.x.ai/v1"
)
# Initialize session state
if "conversation_id" not in st.session_state:
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
c.execute("SELECT conversation_id FROM conversations ORDER BY timestamp DESC LIMIT 1")
result = c.fetchone()
conn.close()
if result:
st.session_state.conversation_id = result[0]
else:
st.session_state.conversation_id = create_new_conversation()
# Sidebar for conversation management
with st.sidebar:
st.title("Conversations")
if st.button("New Conversation"):
st.session_state.conversation_id = create_new_conversation()
st.rerun()
st.subheader("Previous Conversations")
conversations = get_all_conversations()
for conv_id, timestamp in conversations:
dt = datetime.fromisoformat(timestamp)
formatted_time = dt.strftime("%Y-%m-%d %H:%M")
if st.button(f"{formatted_time}", key=conv_id):
st.session_state.conversation_id = conv_id
st.rerun()
# Main chat interface
st.title("Chat with GrokMonster")
# Load conversation history
conversation_history = []
if st.session_state.conversation_id:
conversation_history = get_conversation_history(st.session_state.conversation_id)
# Input box for user message
user_input = st.text_input("Your message:", key="user_input")
if st.button("Send"):
if user_input and st.session_state.conversation_id:
save_message(st.session_state.conversation_id, "user", user_input)
try:
messages = get_conversation_history(st.session_state.conversation_id)
response = client.chat.completions.create(
model="grok-3",
messages=messages,
max_tokens=2000,
temperature=0.7
)
grok_response = response.choices[0].message.content
save_message(st.session_state.conversation_id, "assistant", grok_response)
except Exception as e:
st.error(f"Error: {str(e)}")
st.rerun()
# Display conversation
for msg in conversation_history:
if msg["role"] == "user":
st.write(f"**You**: {msg['content']}")
elif msg["role"] == "assistant":
st.write(f"**Grok**: {msg['content']}")
Step-by-Step Breakdown
1. Setting Up the Database
The app uses SQLite to store conversations and messages. The init_db
function creates two tables:
- conversations: Stores unique conversation IDs and timestamps.
- messages: Stores individual messages with their conversation ID, role (user, assistant, or system), content, and timestamp.
def init_db():
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS conversations
(conversation_id TEXT, timestamp TEXT)
''')
c.execute('''
CREATE TABLE IF NOT EXISTS messages
(id INTEGER PRIMARY KEY, conversation_id TEXT, role TEXT, content TEXT, timestamp TEXT)
''')
conn.commit()
conn.close()
The database is initialized when the app starts with init_db()
.
2. Database Operations
Several functions manage data storage and retrieval:
- save_message: Saves a message to the
messages
table with the conversation ID, role, content, and timestamp. - get_conversation_history: Retrieves all messages for a given conversation ID, formatted as a list of role-content dictionaries.
- get_all_conversations: Fetches all conversation IDs and their timestamps, ordered by recency.
- create_new_conversation: Generates a unique conversation ID, saves it to the
conversations
table, and adds a system message defining Grok's role.
def create_new_conversation():
conversation_id = str(uuid.uuid4())
conn = sqlite3.connect('chat_history.db')
c = conn.cursor()
timestamp = datetime.now().isoformat()
c.execute("INSERT INTO conversations (conversation_id, timestamp) VALUES (?, ?)",
(conversation_id, timestamp))
conn.commit()
conn.close()
# Add system message to the new conversation
system_message = "You are Grok, an extremely intelligent developer and entrepreneur. Specializing in various programming languages."
save_message(conversation_id, "system", system_message)
return conversation_id
3. xAI API Integration
The app uses the OpenAI client to connect to xAI's API:
client = OpenAI(
api_key="you're_api_key_here",
base_url="https://api.x.ai/v1"
)
When a user sends a message, the app:
- Saves the user's message to the database
- Retrieves the full conversation history
- Sends the history to xAI's API
- Saves Grok's response to the database
if st.button("Send"):
if user_input and st.session_state.conversation_id:
save_message(st.session_state.conversation_id, "user", user_input)
try:
messages = get_conversation_history(st.session_state.conversation_id)
response = client.chat.completions.create(
model="grok-3",
messages=messages,
max_tokens=2000,
temperature=0.7
)
grok_response = response.choices[0].message.content
save_message(st.session_state.conversation_id, "assistant", grok_response)
except Exception as e:
st.error(f"Error: {str(e)}")
st.rerun()
4. Streamlit UI
The UI is built with Streamlit and consists of:
- A sidebar for managing conversations
- A main chat interface for displaying messages
- An input box for sending new messages
# Sidebar for conversation management
with st.sidebar:
st.title("Conversations")
if st.button("New Conversation"):
st.session_state.conversation_id = create_new_conversation()
st.rerun()
st.subheader("Previous Conversations")
conversations = get_all_conversations()
for conv_id, timestamp in conversations:
dt = datetime.fromisoformat(timestamp)
formatted_time = dt.strftime("%Y-%m-%d %H:%M")
if st.button(f"{formatted_time}", key=conv_id):
st.session_state.conversation_id = conv_id
st.rerun()
The chat display shows messages with different formatting based on their role:
# Display conversation
for msg in conversation_history:
if msg["role"] == "user":
st.write(f"**You**: {msg['content']}")
elif msg["role"] == "assistant":
st.write(f"**Grok**: {msg['content']}")
Running the Application
To run this application:
- Save the code in a file (e.g.,
app.py
). - Install dependencies:
pip install streamlit openai
. - Replace the API key placeholder with your actual xAI API key.
- Run the app:
streamlit run app.py
.
The app will launch in your browser, allowing you to chat with Grok and manage conversations.
Conclusion
This tutorial demonstrated how to build a chat application with Streamlit and xAI's Grok API. The app provides a simple yet effective interface for interacting with Grok, with the added benefit of conversation persistence through SQLite.
You can extend this application by:
- Adding user authentication
- Implementing conversation titles
- Adding the ability to delete conversations
- Enhancing the UI with custom CSS
- Implementing streaming responses for a more interactive experience
Happy coding!