AIJanuary 15, 20259 min read

Build a Chatbot with Mistral AI and Streamlit

Build an AI chatbot with Mistral AI and Streamlit — streaming replies, conversation memory, and a clean chat UI in pure Python.

Galvan

Galvan

Founder & Creator

Introduction

Conversational AI has become one of the most exciting areas of modern software development. Whether you want to build a customer support bot, a personal study assistant, or a creative writing companion, large language models (LLMs) have made it easier than ever to create intelligent, context-aware applications.

In this guide you will build a fully featured AI chatbot using Mistral AI — one of the most powerful and open-minded LLM providers available today — and Streamlit, the fastest way to turn a Python script into a production-ready web app. By the end you will have a chatbot that supports multi-turn conversations, a configurable system prompt, chat history, and a clean UI.

If you are new to building AI-powered Streamlit apps, you might want to first read our guide on SANGAM AI: The Ultimate AI Toolkit, which covers the broader architecture of multi-modal Python AI projects.


Why Mistral AI?

Mistral AI was founded in 2023 by former Meta and Google DeepMind researchers. It quickly earned a reputation for releasing highly capable open-weight models that can be run locally or accessed via a fast cloud API. Here is a quick comparison of the available Mistral models:

ModelContext WindowBest ForSpeed
mistral-tiny32k tokensQuick, cost-effective responses⚡⚡⚡
mistral-small32k tokensBalanced quality and speed⚡⚡
mistral-medium32k tokensComplex reasoning, coding
mistral-large-latest128k tokensBest quality, long documents
open-mistral-7b32k tokensOpen-weight, self-hostable⚡⚡⚡
open-mixtral-8x7b32k tokensHigh quality open-weight⚡⚡

For this chatbot we will use mistral-small — it gives excellent conversational quality at a very reasonable API cost. You can swap it out for any other model by changing a single line of code.


Prerequisites

Before you begin, make sure you have the following set up:

  • Python 3.9+ — Download from python.org. Mistral's SDK requires Python 3.9 or later.
  • A Mistral AI API key — Sign up at console.mistral.ai and create a new API key from the dashboard. The free tier gives you generous credits to start.
  • Required libraries — Install everything with a single pip command:
  • code
    pip install streamlit mistralai python-dotenv
    PackageVersionPurpose
    streamlit≥ 1.32Web app framework
    mistralai≥ 0.4Official Mistral Python SDK
    python-dotenv≥ 1.0Load API keys from .env file

    Project Structure

    Before writing code, here is the folder layout we will use:

    code
    chatbot/
    ├── chatbot_app.py       ← Main Streamlit application
    ├── .env                 ← API key (never commit this!)
    ├── .gitignore           ← Exclude .env from Git
    └── requirements.txt     ← Python dependencies

    Create a .env file and add your API key:

    code
    MISTRAL_API_KEY=your_actual_api_key_here

    And a .gitignore to keep your key safe:

    code
    .env
    __pycache__/
    .streamlit/

    Step 1: Set Up the Streamlit Page

    Create chatbot_app.py and start with the page configuration and imports:

    code
    import os
    import streamlit as st
    from mistralai.client import MistralClient
    from mistralai.models.chat_completion import ChatMessage
    from dotenv import load_dotenv
    
    load_dotenv()
    
    st.set_page_config(
        page_title="AI Chatbot",
        page_icon="🤖",
        layout="centered"
    )
    st.title("🤖 Mistral AI Chatbot")
    st.caption("Powered by Mistral AI — ask me anything!")

    Using load_dotenv() means your API key stays in the .env file and never appears in your source code.


    Step 2: Initialize Session State

    Streamlit reruns your script from top to bottom every time the user interacts with the page. st.session_state is how you persist data — like the conversation history — across those reruns:

    code
    # Initialize session state variables
    if "messages" not in st.session_state:
        st.session_state.messages = []
    
    if "model" not in st.session_state:
        st.session_state.model = "mistral-small"
    
    if "system_prompt" not in st.session_state:
        st.session_state.system_prompt = "You are a helpful, friendly AI assistant."

    The messages list will hold the full conversation in the format the Mistral API expects: a list of dictionaries with role (either "user" or "assistant") and content fields.


    Step 3: Add the Sidebar Controls

    A good chatbot UI lets users customise their experience. We will put the model selector, system prompt editor, and a clear button in the sidebar:

    code
    with st.sidebar:
        st.header("⚙️ Settings")
    
        st.session_state.model = st.selectbox(
            "Model",
            options=[
                "mistral-tiny",
                "mistral-small",
                "mistral-medium",
                "mistral-large-latest",
            ],
            index=1,
        )
    
        st.session_state.system_prompt = st.text_area(
            "System Prompt",
            value=st.session_state.system_prompt,
            height=150,
            help="Define the chatbot's personality and behaviour here.",
        )
    
        if st.button("🗑️ Clear Chat", use_container_width=True):
            st.session_state.messages = []
            st.rerun()
    
        st.divider()
        st.caption(f"Messages in history: {len(st.session_state.messages)}")

    The system prompt is one of the most powerful tools available when working with LLMs. By changing it, you can turn your chatbot into a coding assistant, a Socratic tutor, a creative fiction writer, or a concise summariser — all without touching the underlying model.


    Step 4: Display the Chat History

    Streamlit's st.chat_message() component makes it trivial to render a WhatsApp-style chat thread:

    code
    # Render existing messages
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

    This loop runs every time the page loads and reconstructs the full conversation from session_state. Each message gets a distinct avatar — a person icon for the user and a robot icon for the assistant — automatically handled by Streamlit.


    Step 5: Handle New User Input

    Now for the main event — capturing user input and generating a response:

    code
    if prompt := st.chat_input("Type your message here..."):
        # Add user message to history and display it
        st.session_state.messages.append({"role": "user", "content": prompt})
        with st.chat_message("user"):
            st.markdown(prompt)
    
        # Build the message list for the API call
        api_messages = [
            ChatMessage(role="system", content=st.session_state.system_prompt)
        ] + [
            ChatMessage(role=m["role"], content=m["content"])
            for m in st.session_state.messages
        ]
    
        # Call Mistral API and stream the response
        api_key = os.getenv("MISTRAL_API_KEY", "")
        client = MistralClient(api_key=api_key)
    
        with st.chat_message("assistant"):
            response_placeholder = st.empty()
            full_response = ""
    
            for chunk in client.chat_stream(
                model=st.session_state.model,
                messages=api_messages,
            ):
                delta = chunk.choices[0].delta.content or ""
                full_response += delta
                response_placeholder.markdown(full_response + "▌")
    
            response_placeholder.markdown(full_response)
    
        st.session_state.messages.append(
            {"role": "assistant", "content": full_response}
        )

    The streaming approach (client.chat_stream()) sends the response token-by-token, so users see words appearing as the model generates them — just like ChatGPT. The cursor gives a nice typing-in-progress effect.


    Step 6: Run the App

    code
    streamlit run chatbot_app.py

    Open http://localhost:8501 and start chatting!


    Complete Code

    Here is the full chatbot_app.py file with all steps combined:

    code
    import os
    import streamlit as st
    from mistralai.client import MistralClient
    from mistralai.models.chat_completion import ChatMessage
    from dotenv import load_dotenv
    
    load_dotenv()
    
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖", layout="centered")
    st.title("🤖 Mistral AI Chatbot")
    st.caption("Powered by Mistral AI — ask me anything!")
    
    for key, default in [("messages", []), ("model", "mistral-small"),
                         ("system_prompt", "You are a helpful, friendly AI assistant.")]:
        if key not in st.session_state:
            st.session_state[key] = default
    
    with st.sidebar:
        st.header("⚙️ Settings")
        st.session_state.model = st.selectbox(
            "Model",
            ["mistral-tiny", "mistral-small", "mistral-medium", "mistral-large-latest"],
            index=1,
        )
        st.session_state.system_prompt = st.text_area(
            "System Prompt", value=st.session_state.system_prompt, height=150
        )
        if st.button("🗑️ Clear Chat", use_container_width=True):
            st.session_state.messages = []
            st.rerun()
        st.divider()
        st.caption(f"Messages: {len(st.session_state.messages)}")
    
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])
    
    if prompt := st.chat_input("Type your message here..."):
        st.session_state.messages.append({"role": "user", "content": prompt})
        with st.chat_message("user"):
            st.markdown(prompt)
    
        api_messages = [
            ChatMessage(role="system", content=st.session_state.system_prompt)
        ] + [ChatMessage(role=m["role"], content=m["content"])
             for m in st.session_state.messages]
    
        client = MistralClient(api_key=os.getenv("MISTRAL_API_KEY", ""))
        with st.chat_message("assistant"):
            placeholder = st.empty()
            full_response = ""
            for chunk in client.chat_stream(model=st.session_state.model, messages=api_messages):
                full_response += chunk.choices[0].delta.content or ""
                placeholder.markdown(full_response + "▌")
            placeholder.markdown(full_response)
        st.session_state.messages.append({"role": "assistant", "content": full_response})

    Understanding the Mistral API

    Here is a summary of the key Mistral API concepts used in this project:

    ConceptWhat it DoesExample
    ChatMessage(role, content)Wraps a single messageChatMessage(role="user", content="Hello")
    system roleSets the AI's personality"You are a Python expert."
    user roleThe human's message"Explain list comprehensions"
    assistant roleThe AI's previous replyUsed for multi-turn context
    client.chat()Single blocking responseGood for short interactions
    client.chat_stream()Token-by-token streamingBest for chat UIs
    chunk.choices[0].delta.contentThe next token in stream"Hello", " world", "!"

    Customising the System Prompt

    The system prompt is your most powerful tool. Here are some examples of how to specialise your chatbot:

    PersonaSystem Prompt
    Python Tutor"You are an expert Python instructor. Explain concepts clearly with code examples. Always suggest best practices."
    Code Reviewer"You are a senior software engineer doing code review. Be constructive and precise. Point out bugs and suggest improvements."
    Socratic Teacher"You are a Socratic tutor. Never give direct answers — guide the user to discover the answer through questions."
    Recipe Assistant"You are a professional chef. Suggest recipes based on ingredients the user provides. Always include cooking times and serving sizes."
    English Corrector"You are an English grammar expert. Rewrite the user's text with correct grammar and improved style. Explain each change briefly."

    Adding Memory: How Context Windows Work

    When you send a message to Mistral, you send the entire conversation history with every request. This is how the model "remembers" previous messages — it can see everything that was said.

    Here is the structure of a typical API call with history:

    code
    [
      {"role": "system",    "content": "You are a helpful assistant."},
      {"role": "user",      "content": "What is Python?"},
      {"role": "assistant", "content": "Python is a high-level programming language..."},
      {"role": "user",      "content": "What is it good for?"},   ← new message
    ]

    The model uses the full history to generate a contextually relevant answer to "What is it good for?" — it knows "it" refers to Python because the prior turns are included.

    Important: As conversations grow, they consume more tokens. If the total message length exceeds the model's context window (32k or 128k tokens), older messages will need to be truncated. For long sessions you can implement a sliding window: keep only the last N messages in session_state.messages.


    Deploying to Streamlit Cloud

    Once your chatbot is working locally, you can share it with the world in minutes using Streamlit Community Cloud:

  • Push your project to a public GitHub repository (make sure .env is in .gitignore).
  • Go to share.streamlit.io and connect your GitHub account.
  • Select your repository and set the main file path to chatbot_app.py.
  • Under Advanced settings → Secrets, add your MISTRAL_API_KEY — Streamlit Cloud stores it securely as a secret, so you do not need the .env file in production. Access it with st.secrets["MISTRAL_API_KEY"] instead of os.getenv().
  • Click Deploy — your chatbot is live!

  • Now that you have a working chatbot, here are some related projects on this blog that complement what you have built:

  • SANGAM AI — All-in-One AI Toolkit: Extends the Mistral text generation module into a full multi-modal app with speech and image capabilities.
  • Sentiment Analysis App: Combine sentiment analysis with your chatbot to detect when users are frustrated and change the response tone accordingly.
  • Text-to-Speech with gTTS and Streamlit: Add voice output to your chatbot so it can speak its responses aloud.

  • Troubleshooting

    ProblemLikely CauseFix
    AuthenticationErrorWrong or missing API keyCheck .env and os.getenv() call
    Responses stop mid-sentenceContext window exceededLimit session_state.messages to last 20
    Very slow first responseModel cold startSwitch to mistral-tiny for faster responses
    ModuleNotFoundError: mistralaiLibrary not installedRun pip install mistralai
    Chat history lost on refreshSession state clearedThis is expected in Streamlit — consider persisting to a file or database

    Conclusion

    You have built a fully functional, streaming AI chatbot with Mistral AI and Streamlit. The app supports multi-turn conversations, a configurable system prompt, model switching, and a clean real-time streaming UI — all in under 60 lines of Python.

    From here, the possibilities are endless: add document upload so users can chat with their PDFs, integrate with a database to persist chat history, or chain multiple API calls to build a fully autonomous AI agent.

    Resources:

  • Mistral AI Documentation
  • Mistral API Reference
  • Streamlit Documentation
  • Streamlit Community Cloud