- Streamlit is een snelle manier om aangepaste AI-chatbotinterfaces te bouwen, maar heeft meer flexibiliteit nodig dan de ingebouwde chatelementen bieden.
- Botpress Chat API verzorgt de chatbotlogica, informatieopvraging en workflows, beschikbaar via een aangepaste Python-client.
- De Streamlit-app beheert gesprekken, streamt antwoorden en werkt met dynamische gebruikerssessies.
Voor zover ik weet is Streamlit de snelste manier om een aanpasbare webapplicatie snel op te zetten. Als je een AI-chatbot wilt bouwen en deze op je eigen front-end wilt inzetten, kan ik geen betere optie bedenken.
Het enige minpunt is de bibliotheek met chatelementen. Die zijn vrij specifiek afgestemd op de API en Python-client van OpenAI.
Dat is op zich prima – met een paar regels code kun je werken met de beste technologie die er is, en dat is… prima.
Maar het is niet alles.
Wat als je meer controle wilt over je bot? Misschien wil je bijvoorbeeld een workflow met meerdere stappen, of retrieval-augmented generation (RAG). Deze extra lagen functionaliteit betekenen meestal dat je verschillende bibliotheken met allerlei afhankelijkheden moet combineren.
Of toch niet?
In deze tutorial bouw ik een Streamlit-chatbotclient. Ik laat je een interface zien voor snelle iteratie en zeer aanpasbare chatbots. Daarna leer je hoe je de chatbot integreert met een zelfgebouwde OpenAI-achtige Python-client.
Als je aan het prototypen bent, moeten afhankelijkheden en technische details je niet tegenhouden.
En in de geest van snel prototypen: als je de tutorial wilt overslaan en meteen wilt experimenteren, de code staat op GitHub.
Succes 💣
Stap 1: Bouw de chatbotlogica
Of het nu gaat om workflowautomatisering of een afspraakplanner-chatbot, de mogelijkheden zijn hier eindeloos.
Ik raad je aan om de vele toepassingen van GenAI-chatbots te bekijken als je inspiratie zoekt. Voor de eenvoud gebruik ik mijn inmiddels hopelijk bekende sommelier, Winona.
Onze slimme, behulpzame bot is in een paar stappen te realiseren. Ik houd het kort, maar er zijn veel uitgebreide, zeer nuttige tutorials die je kunt bekijken.
1. Geef instructies
In de studio gaan we naar Home in de zijbalk links.

Je ziet nu de sectie Instructions prominent in beeld. Klik erop om de instructies in gewone tekst toe te voegen of aan te passen.

Hiermee geef je je bot richting, persoonlijkheid en grenzen. Met duidelijke taal kun je je bot effectief sturen naar het gewenste gedrag. Laat hem menselijker klinken, en
2. Bouw de Flow
Hier zit de kern van de persoonlijkheid van de bot: toegang tot specifieke informatie, vaste stappen, code-uitvoering, enzovoort.
Onderschrijf de kracht van eenvoud niet. Eén autonoom knooppunt kan zich meten met de functionaliteit van reasoning agents. Ik heb er één gekoppeld aan mijn Knowledge Base (KB).

3. Voeg de Knowledge Base toe
Als de instructies voor de sfeer zijn, is de KB voor de feiten. In mijn geval zijn dat de wijnen uit de Wine Reviews dataset: een lijst met wijnen, beschrijvingen en prijzen. Ik gebruik dit als de wijnvoorraad voor onze sommelier-bot.
Ik klik op Tables in het linkerpaneel, kies linksboven New Table en geef de tabel een duidelijke naam.

Klik rechtsboven op de verticale ellipsis (⋮) en kies Importeren.

Sleep je .csv-bestand in het venster dat verschijnt en volg de stappen op het scherm.
Om de tabel beschikbaar te maken voor je bot, ga je naar Knowledge Bases in de linkerzijbalk.

Klik op het kleine groene tabelpictogram en selecteer de juiste bron. Klik op Add tables.

Zorg dat je flow toegang heeft tot de Knowledge Base en je bent klaar om te starten.

Stap 2: Voeg de Chat API-integratie toe
Het contactpunt tussen de bot en onze lokale client is de Chat API. Om die toe te voegen aan onze bot, scroll ik naar Communication Channels en klik op … More.

Bekijk gerust de integraties als je wilt. Wij zoeken Chat. Ik moest even scrollen om hem te vinden.

Klik op de integratie en kies Install Integration in het venster dat verschijnt.

Na installatie zie je de Chat API ID aan het einde van de webhook-URL. Die heb je later nodig.
Stap 3: Schrijf de Python-client
De Chat API biedt verschillende endpoints om crud-bewerkingen uit te voeren op gebruikers, gesprekken en berichten. Zoals beloofd, verpak ik deze in een Python-client die een OpenAI-client kan vervangen.
1. Voeg je inloggegevens toe
class BotpressClient:
def __init__(self, api_id=None, user_key=None):
self.api_id = api_id or os.getenv("CHAT_API_ID")
self.user_key = user_key or os.getenv("USER_KEY")
self.base_url = f"{BASE_URI}/{self.api_id}"
self.headers = {
**HEADERS,
"x-user-key": self.user_key,
}
Je kunt je Chat API ID toevoegen aan een .env-bestand – dat helpt bij het debuggen, maar is niet strikt noodzakelijk. We regelen de API ID en gebruikerssleutel als we de Streamlit-app bouwen.
Ik bewaar BASE_URI en HEADERS in een apart constants.py-bestand, voor het overzicht.
# constants.py
BASE_URI = "https://chat.botpress.cloud"
HEADERS = {
"accept": "application/json",
"Content-Type": "application/json",
}
2. Maak de request-methoden
def _request(self, method, path, json=None):
url = f"{self.base_url}{path}"
try:
response = requests.request(method, url, headers=self.headers, json=json)
response.raise_for_status()
return response.json()
except requests.HTTPError:
return response.status_code, response.text
# --- Core API Methods ---
def get_user(self):
return self._request("GET", "/users/me")
def create_user(self, name, id):
user_data = {"name": name, "id": id}
return self._request("POST", "/users", json=user_data)
def set_user_key(self, key):
self.user_key = key
self.headers["x-user-key"] = key
def create_and_set_user(self, name, id):
new_user = self.create_user(name, id)
self.set_user_key(new_user["key"])
def create_conversation(self):
return self._request("POST", "/conversations", json={"body": {}})
def list_conversations(self):
return self._request("GET", "/conversations")
def get_conversation(self, conversation_id):
return self._request("GET", f"/conversations/{conversation_id}")
def create_message(self, message, conversation_id):
payload = {
"payload": {"type": "text", "text": message},
"conversationId": conversation_id,
}
return self._request("POST", "/messages", json=payload)
def list_messages(self, conversation_id):
return self._request("GET", f"/conversations/{conversation_id}/messages")Zoals gezegd, komen deze bijna allemaal overeen met een endpoint in de API. Ik verpak ze alleen in een klasse.
3. Maak een SSE-listener
Dit is het enige stukje 'hackwerk'. Om te luisteren naar gespreksupdates en deze door te geven aan een Streamlit-frontend, heeft de client een methode nodig om te luisteren naar – en data te ontvangen van – server-sent events van onze bot.
def listen_conversation(self, conversation_id):
url = f"{self.base_url}/conversations/{conversation_id}/listen"
for event in sseclient.SSEClient(url, headers=self.headers):
print(event.data)
if event.data == "ping":
continue
data = json.loads(event.data)["data"]
yield {"id": data["id"], "text": data["payload"]["text"]}Deze functie neemt het conversation_id (dat in de app wordt opgehaald) en levert binnenkomende data zodra die er is.
Stap 4: Maak de Streamlit-app
Nu alles klaarstaat, is het tijd om de chatbot te bouwen. Ik volg hierbij de Streamlit-gids voor het bouwen van een LLM-chatapp – met wat extra functies.
1. Pas de standaardcode aan
In theorie kun je de app werkend krijgen met minimale aanpassingen aan de standaardcode uit het Streamlit-voorbeeld.
# app.py
from client import BotpressClient
import streamlit as st
from constants import CONVERSATION_ID
st.title("Botpress Front-end for Streamlit")
client = BotpressClient(
api_id=st.secrets["CHAT_API_ID"], user_key=st.secrets["USER_KEY"]
)
if "messages" not in st.session_state:
messages = client.list_messages(CONVERSATION_ID)
next_token = messages["meta"]["nextToken"]
st.session_state.messages = messages["messages"][::-1]
for message in st.session_state.messages:
with st.chat_message(message["userId"]):
st.markdown(message["payload"]["text"])
if prompt := st.chat_input("*wine*-d it up"):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
client.create_message(prompt, conversation_id=CONVERSATION_ID)
with st.chat_message("assistant"):
response_box = st.empty()
last_rendered = ""
for message in client.listen_conversation(CONVERSATION_ID):
message_id = message["id"]
message_text = message["text"]
if message_id != last_rendered:
last_rendered = message_id
response_box.markdown(message_text)
st.session_state.messages.append(
{"role": "assistant", "content": message_text}
)
We lezen hier geheime variabelen uit. Maak dus een .streamlit/secrets.toml-bestand aan en zet je variabelen daarin:
CHAT_API_ID = ”YOUR_API_ID”
USER_KEY = ”YOUR_USER_KEY”Het meeste werk gebeurt hier:
with st.chat_message("assistant"):
response_box = st.empty()
last_rendered = ""
for message in client.listen_conversation(CONVERSATION_ID):
message_id = message["id"]
message_text = message["text"]
if message_id != last_rendered:
last_rendered = message_id
response_box.markdown(message_text)
st.session_state.messages.append(
{"role": "assistant", "content": message_text}
)
waar de client gekoppeld is aan de chatelementen om berichten te versturen en te ontvangen.
Dit werkt, maar het is om een paar redenen niet ideaal:
- Je moet een nieuw gesprek apart aanmaken.
- Oude berichten worden anders opgemaakt dan nieuwe, omdat ze geen rol (user of assistant) hebben.
- Je kunt niet tussen gesprekken wisselen.
2. Maak gesprekken dynamisch aan
Vanaf nul maak ik automatisch een nieuw gesprek aan of open ik het meest recente:
# app.py
from client import BotpressClient
import streamlit as st
st.title("Botpress Front-end for Streamlit")
client = BotpressClient(
api_id=st.secrets["CHAT_API_ID"], user_key=st.secrets["users"][0]["key"]
)
# user info
user = client.get_user()
user_id = user["user"]["id"]
conversations = client.list_conversations()["conversations"]
conversation_ids = [conv["id"] for conv in conversations]
# conversation
def create_conversation():
res = client.create_conversation()
print(f"Created new conversation: {res}")
conversation_id = res["conversation"]["id"]
st.session_state.active_conversation = conversation_id
st.session_state.messages = []
st.rerun()
if not conversations:
create_conversation()
if "active_conversation" not in st.session_state:
st.session_state["active_conversation"] = conversations[0]["id"]
Let op: ik heb de geheime sleutels aangepast zodat je meerdere gebruikers kunt opslaan. Pas je .streamlit/secrets.toml-bestand hierop aan:
[[users]]
key = "your_user_key"Je kunt dit blok zo vaak herhalen als je wilt, waarbij je gebruikers opslaat als een array van tabellen.
3. Laat gebruikers gesprekken aanmaken en wisselen
Zoals de titel zegt: hiermee maak je bovenaan een dropdown met een knop om een gesprek te kiezen.
col1, col2 = st.columns([5, 1])
with col1:
conversation_id = st.selectbox(
"Select Conversation",
options=[conv["id"] for conv in conversations],
index=conversation_ids.index(st.session_state.active_conversation),
)
with col2:
st.markdown("<div style='height: 1.9em'></div>", unsafe_allow_html=True)
if st.button("➕"):
create_conversation()
selected_conversation = client.get_conversation(conversation_id)4. Wijs de juiste rol toe aan eerdere berichten
We lossen het opmaakprobleem hierboven op door aan elk eerder bericht de rol user of assistant toe te wijzen:
if (
"messages" not in st.session_state
or st.session_state.get("active_conversation") != conversation_id
):
st.session_state.active_conversation = conversation_id
st.session_state.messages = []
messages = client.list_messages(conversation_id)
next_token = messages["meta"].get("nextToken")
for message in messages["messages"][::-1]:
role = "user" if message["userId"] == user_id else "assistant"
text = message["payload"]["text"]
st.session_state.messages.append({"role": role, "content": text})Hiermee voldoet onze code aan de structuur die Streamlit verwacht.
5. Voeg de berichtlogica toe
Dit is grotendeels hetzelfde als voorheen, maar aangepast aan de nieuwe structuur.
# display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if prompt := st.chat_input("*wine*-d it up"):
st.session_state.messages.append({"role": "user", "content": prompt})
client.create_message(prompt, conversation_id=conversation_id)
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
stream = client.listen_conversation(conversation_id=conversation_id)
response = st.write_stream(stream)
st.session_state.messages.append({"role": "assistant", "content": response})5. Maak een gebruiker aan
De logica is klaar, maar je moet nog een gebruiker aanmaken om de app te draaien. Ik heb ervoor gekozen dit apart te doen om het aanmelden bij een dienst te simuleren. Gelukkig heb ik daar ook een script voor geschreven:
# create_user.py
import argparse
from pathlib import Path
from client import *
from constants import *
secrets_path = Path(".streamlit") / "secrets.toml"
template = """[[users]]
key="{}"
"""
client = BotpressClient()
def create_user(name, id, add_to_secrets=True):
res = client.create_user(name, id)
if not add_to_secrets:
return res
secrets_path.touch(exist_ok=True)
with open(secrets_path, "a") as f:
f.write(template.format(res["user"]["id"], res["key"]))
return res
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Create a Botpress user and optionally store secrets."
)
parser.add_argument("--name", required=True, help="Display name of the user.")
parser.add_argument(
"--id", required=True, help="User ID. If omitted, one is generated by the API."
)
parser.add_argument("--chat_api_id", help="ID for the Botpress Chat API integration. Taken from `.env` file if not provided.")
parser.add_argument(
"--no-secrets",
action="store_true",
help="Do not append to .streamlit/secrets.toml.",
)
args = parser.parse_args()
print(f"Creating user: {args.name} (ID: {args.id or 'auto-generated'})")
result = create_user(name=args.name, id=args.id, add_to_secrets=not args.no_secrets)
print("✅ User created:")
print(result)
Als je je Chat API ID hebt, kun je het volgende uitvoeren:
python create_user.py –name JOUW_NAAM –id EEN_GEBRUIKERS_ID –chat_api_id JOUW_CHAT_API_ID
Hiermee wordt de gebruiker aangemaakt en toegevoegd aan je secrets-bestand.
Stap 5: Start de applicatie
Nu je de logica hebt gebouwd en je gebruiker hebt aangemaakt, is het tijd om deze applicatie uit te proberen. Installeer de afhankelijkheden en voer uit:
streamlit run app.py
En zo zie je onze bot in volle glorie.

Start vandaag nog met een Streamlit-chatbot
Als je aan het prototypen bent met Streamlit, weet je dat maatwerk niet ten koste mag gaan van gebruiksgemak. Chatbots zijn er om problemen op te lossen—niet om ze te veroorzaken.
Botpress biedt een visuele drag-and-drop builder, tientallen officiële integraties en toegankelijke API-eindpunten. Zo kun je bouwen, itereren en uitrollen over meerdere communicatiekanalen.
Begin vandaag nog met bouwen. Het is gratis.
Veelgestelde vragen
Waarom zou ik Streamlit kiezen boven andere front-end frameworks voor het bouwen van een chatbot?
Je kiest voor Streamlit als je snel een Python-gebaseerde oplossing wilt waarmee je interactieve apps kunt prototypen zonder front-end kennis, omdat het UI-elementen zoals chatcomponenten en statusbeheer met minimale code afhandelt.
Is een Streamlit-chatbot geschikt voor productiegebruik of alleen voor prototypes?
Een Streamlit-chatbot is ideaal voor prototypes en interne tools, maar voor publieke productie-apps met veel verkeer of geavanceerde opmaak heb je mogelijk extra lagen nodig, zoals reverse proxies, beveiligingsmaatregelen en eventueel een robuuster front-end framework voor schaalbaarheid.
Hoeveel kan het uiterlijk en de gebruikerservaring van een Streamlit-chatbot aangepast worden?
Met Streamlit kun je basisstijlen zoals kleuren, lettertypes en lay-out aanpassen, maar het is minder flexibel dan traditionele webframeworks; voor echt maatwerk moet je eigen HTML/CSS of JavaScript toevoegen, wat mogelijk is maar meer complexiteit met zich meebrengt dan de ingebouwde widgets van Streamlit.
Kan ik een Streamlit-chatbot integreren in een bestaande website, of moet deze altijd zelfstandig draaien?
Een Streamlit-chatbot draait meestal als een zelfstandige webapp op een eigen URL, maar je kunt hem via een iframe in een bestaande website insluiten. Houd dan wel rekening met styling en beveiliging om de gebruikerservaring soepel te houden.
Wat kost het om een Streamlit-chatbot te implementeren voor openbaar gebruik?
Het inzetten van een Streamlit-chatbot kan gratis zijn als je deze lokaal of op Streamlit Community Cloud voor kleinere apps host. Voor grootschalig openbaar gebruik liggen de kosten op cloudplatforms zoals Heroku, AWS of DigitalOcean tussen ongeveer $5 en $50 per maand, afhankelijk van het verkeer en de vereiste beschikbaarheid.





.webp)
