← Back to Python series
🛠
Practice Projects · ★★★★
Markov chains · Text processing · Probability · curses · textual · Widgets · Keyboard events

Project 15 — Markov Chain Chatbot · Project 16 — TUI App with curses / textual

Build a text generator chatbot using Markov chains. Train it on any text corpus and generate statistically plausible responses. Build a terminal user interface (TUI) for one of your earlier projects. Use curses for low-level control or the modern textual framework for high-level widgets.

Markov chainNLPtext generationprobabilitydictTUIcursestextualterminal UIwidgets
Duration
⏱ 3 hours + 4 hours
Level
📊 Advanced Applied
Prerequisite
🎯 Intermediate Weeks 2–4
OUTCOME
A Markov chain text generator trained on a text corpus / A full TUI application with menus, input fields, and keyboard navigation

What you'll learn

  • 1Build an n-gram frequency model from text
  • 2Generate text by sampling from the model
  • 3Handle sentence boundaries naturally
  • 4Train on multiple corpora and blend responses
  • 5Set up a curses or textual application skeleton
  • 6Render windows, panels, and text widgets
  • 7Handle keyboard input and navigation
  • 8Port an existing CLI app to TUI

Project 15 — Markov Chain Chatbot

Build a text generator chatbot using Markov chains. Train it on any text corpus and generate statistically plausible responses.

Algorithm

A Markov chain model predicts the next word based only on the previous N words (N-gram). For N=2: given (word1, word2), sample the most likely word3 from training data.

python
from collections import defaultdict
import random

class MarkovChain:
    def __init__(self, n=2):
        self.n = n
        self.model = defaultdict(list)

    def train(self, text: str):
        words = text.split()
        for i in range(len(words) - self.n):
            key = tuple(words[i:i+self.n])
            self.model[key].append(words[i+self.n])

    def generate(self, length=50, seed=None):
        if seed is None:
            seed = random.choice(list(self.model.keys()))
        output = list(seed)
        for _ in range(length - self.n):
            key = tuple(output[-self.n:])
            nexts = self.model.get(key)
            if not nexts: break
            output.append(random.choice(nexts))
        return ' '.join(output)

Project 16 — TUI App with curses / textual

Build a terminal user interface (TUI) for one of your earlier projects. Use curses for low-level control or the modern textual framework for high-level widgets.

Option A: curses (stdlib)

python
import curses

def main(stdscr):
    curses.curs_set(0)
    stdscr.clear()
    h, w = stdscr.getmaxyx()
    stdscr.addstr(h//2, w//2-10, "Hello from curses!")
    stdscr.addstr(h-1, 0, "Press q to quit")
    stdscr.refresh()
    while True:
        key = stdscr.getch()
        if key == ord("q"):
            break

curses.wrapper(main)

Option B: textual (third-party)

python
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Button, Label

class MyApp(App):
    def compose(self) -> ComposeResult:
        yield Header()
        yield Label("Hello, Textual!")
        yield Button("Click me", id="btn")
        yield Footer()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.query_one(Label).update("Button was pressed!")

if __name__ == "__main__":
    MyApp().run()

Suggested project: TUI To-Do

  • Main pane: task list with arrow-key navigation
  • Status bar: task count and current filter
  • Keybindings: a=add, d=delete, space=toggle done, q=quit, /=search
  • Input dialog: popup for task title

📝 Exercises

Try them yourself first, then open the solution to compare.

Exercise 1

Build the Markov chatbot

Goal: Train a Markov model on a text file and create a chatbot loop.

Requirements
  • Build bigram model from corpus
  • Generate 50-word responses
  • Interactive chat loop
  • Load corpus from file
Exercise 2

Build a TUI app

Goal: Port your to-do app (Project 5) to a TUI using curses or textual.

Requirements
  • Task list with keyboard navigation
  • Add/delete/toggle done via keybindings
  • Status bar with count
  • Search/filter pane
Grading
  • · Renders correctly in terminal — 30%
  • · Keyboard navigation — 30%
  • · CRUD operations — 30%
  • · No crashes on resize — 10%
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗

Comments 0

No comments yet. Be the first.

Only members can comment.

Comments with ads, abuse, personal information or illegal content are hidden or removed. Comments are shown with your nickname. Privacy Policy