← 파이썬 강의 목록으로
🤖
실습 프로젝트 (Practice) · ★★★★
규칙 기반 + 명령어 모드 · 표·진행바·컬러

Lv4 · 콘솔 챗봇 · Lv4 · TUI 앱

정규식 규칙 기반의 콘솔 챗봇. /quit /clear /save /load /history 명령어와 대화 이력 JSON 저장을 지원합니다. rich 라이브러리로 표/패널/컬러를 사용한 풍부한 콘솔 UI. 미설치 시 plain 모드로 폴백하는 안전 패턴까지.

regexJSON챗봇richtextualTUI
소요 시간
⏱ 5~8시간 + 5~8시간
난이도
📊 고급 응용
선수 조건
🎯 고급 7주차 (requests)
결과물
정규식과 람다로 규칙 엔진 / 라이브러리 의존성과 graceful fallback

이 강의에서 배우는 것

  • 1정규식 규칙으로 입력 매칭
  • 2/명령어 모드 분기
  • 3대화 이력 JSON 저장/불러오기
  • 4rich 의 Table, Panel 사용
  • 5ImportError 를 graceful 하게 처리
  • 6설치: pip install rich

Lv4 · 콘솔 챗봇

정규식 규칙 기반의 콘솔 챗봇. /quit /clear /save /load /history 명령어와 대화 이력 JSON 저장을 지원합니다.

프로젝트 개요

  • /quit /exit /help /clear /save /load /history
  • 규칙 기반 응답 (정규식 + 응답 또는 람다)
  • API 기반은 선택 옵션 (.env + python-dotenv)

도전 과제

  • 토큰 사용량 추적
  • 비동기 다중 모델

채점 체크리스트

  • 명령어 모드
  • 이력 저장/불러오기
  • 정규식 매칭

Lv4 · TUI 앱 (rich/textual)

rich 라이브러리로 표/패널/컬러를 사용한 풍부한 콘솔 UI. 미설치 시 plain 모드로 폴백하는 안전 패턴까지.

프로젝트 개요

  • rich 또는 textual 사용
  • 예: To-Do 또는 가계부를 TUI 로 재작성
  • 미설치 시 plain 모드 폴백

도전 과제

  • textual 풀스크린 + 키보드 단축키
  • Live 로 실시간 갱신

설치

bash
pip install rich
# 또는
pip install textual

채점 체크리스트

  • rich 사용
  • ImportError 폴백
  • 표 출력

💻 예제 (examples)

실제로 실행해 결과를 확인할 수 있는 예제 코드입니다.

solution.py— 전체 동작 코드 (규칙 기반)
CODE
"""규칙 기반 콘솔 챗봇 — API 키 없이 동작"""
import json
import re
from pathlib import Path
from datetime import datetime

HISTORY = Path("chat_history.json")

RULES = [
    (r"안녕|hello|hi", "안녕하세요!"),
    (r"이름|누구", "저는 학습용 챗봇입니다."),
    (r"날씨", "죄송해요, 실시간 날씨는 못 알려드려요."),
    (r"파이썬|python", "파이썬은 1991년에 발표된 인터프리터 언어예요."),
    (r"감사|고마워|thanks", "천만에요!"),
    (r"(\d+)\s*\+\s*(\d+)", lambda m: f"= {int(m.group(1)) + int(m.group(2))}"),
]

def respond(text):
    for pattern, reply in RULES:
        m = re.search(pattern, text)
        if m:
            return reply(m) if callable(reply) else reply
    return "잘 모르겠어요. 다시 말씀해주세요."

def save(history):
    HISTORY.write_text(json.dumps(history, ensure_ascii=False, indent=2), encoding="utf-8")

def load():
    return json.loads(HISTORY.read_text(encoding="utf-8")) if HISTORY.exists() else []

def main():
    history = []
    print("챗봇 시작 (/quit 으로 종료, /help 로 명령어)")
    while True:
        user = input("\nyou: ").strip()
        if not user: continue
        if user.startswith("/"):
            cmd = user[1:]
            if cmd in ("quit", "exit"): break
            elif cmd == "help":
                print("/clear /save /load /history /quit")
            elif cmd == "clear": history = []; print("이력 초기화")
            elif cmd == "save": save(history); print("저장됨")
            elif cmd == "load": history = load(); print(f"불러옴 ({len(history)}개)")
            elif cmd == "history":
                for h in history[-5:]:
                    print(f"  [{h['time']}] {h['who']}: {h['text']}")
            continue
        bot_reply = respond(user)
        ts = datetime.now().strftime("%H:%M:%S")
        history.append({"time": ts, "who": "user", "text": user})
        history.append({"time": ts, "who": "bot", "text": bot_reply})
        print(f"bot: {bot_reply}")

if __name__ == "__main__":
    main()
▶ 실행 결과
챗봇 시작 (/quit 으로 종료, /help 로 명령어)

you: 안녕
bot: 안녕하세요!

you: 3+4
bot: = 7

you: /save
저장됨

you: /quit
solution.py— rich 표 + 폴백
CODE
"""TUI To-Do (rich) — pip install rich"""

try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
    HAS_RICH = True
except ImportError:
    HAS_RICH = False

todos = [
    {"id": 1, "task": "우유 사기", "priority": "보통", "done": False},
    {"id": 2, "task": "책 반납", "priority": "높음", "done": True},
    {"id": 3, "task": "운동", "priority": "낮음", "done": False},
]

PRIORITY_STYLE = {"높음": "red", "보통": "yellow", "낮음": "green"}

def render_rich():
    console = Console()
    table = Table(title="📋 My To-Do", show_lines=True, header_style="bold cyan")
    table.add_column("번호", justify="right", style="cyan")
    table.add_column("상태", justify="center")
    table.add_column("우선순위", justify="center")
    table.add_column("할 일")
    for t in todos:
        mark = "[green]✓ 완료[/]" if t["done"] else "[yellow]○ 진행[/]"
        prio = f"[{PRIORITY_STYLE[t['priority']]}]{t['priority']}[/]"
        task = f"[strike]{t['task']}[/]" if t["done"] else t["task"]
        table.add_row(str(t["id"]), mark, prio, task)
    console.print(table)
    pending = sum(1 for t in todos if not t["done"])
    console.print(Panel(f"미완료: [bold red]{pending}[/]개  /  전체 {len(todos)}개", style="dim"))

def render_plain():
    print("📋 My To-Do (plain mode — pip install rich 권장)")
    for t in todos:
        mark = "[x]" if t["done"] else "[ ]"
        print(f"  {t['id']}. {mark}[{t['priority']}] {t['task']}")

def main():
    if HAS_RICH:
        render_rich()
    else:
        print("⚠️ rich 미설치. plain 모드로 출력.")
        render_plain()

if __name__ == "__main__":
    main()
▶ 실행 결과
(rich 설치 시) 컬러 표 출력
(미설치 시)
⚠️ rich 미설치. plain 모드로 출력.
📋 My To-Do (plain mode — pip install rich 권장)
  1. [ ][보통] 우유 사기
  2. [x][높음] 책 반납
  3. [ ][낮음] 운동

📝 과제 (exercises)

직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.

과제 1

프로젝트 구현

목표: 위 사양대로 직접 작성한다.

요구사항
  • RULES 리스트
  • /명령어 모드
  • 이력 JSON 저장
💡 힌트

callable(reply) 로 함수/문자열 분기

입출력 예시
bot: 안녕하세요!
채점
  • · 정규식 매칭
  • · 명령어
▶정답 코드 펼치기 / 접기
SOLUTION
# 위 solution.py 와 동일
▶ 실행 결과
(예제 참고)
과제 2

프로젝트 구현

목표: 위 사양대로 직접 작성한다.

요구사항
  • try/except ImportError
  • rich.Table
  • polo 폴백
💡 힌트

table.add_column / table.add_row

입출력 예시
📋 My To-Do
채점
  • · 폴백 동작
  • · rich 표
▶정답 코드 펼치기 / 접기
SOLUTION
# 위 solution.py 와 동일
▶ 실행 결과
(예제 참고)
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 주세요.

댓글은 회원만 쓸 수 있습니다.

광고·욕설·비방·개인정보·불법 내용이 담긴 댓글은 숨기거나 지웁니다. 댓글은 닉네임과 함께 공개됩니다. 개인정보처리방침