DE EN

PyBuddy CLI

The Final Project โ€” all learned concepts in one interactive assistant

๐Ÿ• 90 Min ๐Ÿ† Final Project Python 3.10+

What awaits you?

In this project you build PyBuddy CLI โ€” an interactive command-line assistant, that combines all concepts from the 13 chapters. In the end you have a complete program, that you can proudly showcase in your portfolio.

Project Overview

PyBuddy CLI is a personal assistant in the terminal. It greets the user, saves a profile, runs small tools and remembers everything in a JSON file. This project uses all chapter concepts:

Chapter 01: Variables for username, Level, XP
Chapter 02: input() and f-strings for the greeting
Chapter 03: Operators for XP calculations
Chapter 04: Conditions for menu decisions
Chapter 05: while loop for the main menu
Chapter 06: Lists for tasks and badges
Chapter 07: Dictionary for the user profile
Chapter 08: Functions for all tools
Chapter 09: Module (datetime, json, random)
Chapter 10: JSON file for saving the profile
Chapter 11: Optional: Weather API integration
Chapter 12: AI-assisted code review of your project

Requirements

Your PyBuddy CLI must have the following features. Work through the points step by step:

  1. Greeting: Asks for the name and greets the user personally.

  2. Profile System: Saves name, level, XP and badges in a dictionary.

  3. Main Menu: Shows a menu with options and repeats until "exit".

  4. XP Calculator: Calculates total XP from base XP, multiplier and bonus.

  5. To-Do List: Add, display and complete tasks.

  6. Random Quote: Shows a random motivational quote from a list.

  7. Save & Load: Save profile as JSON and reload on startup.

Step by Step

Step 1: Project Structure

Create a folder pybuddy-cli/ with two files:

bash
pybuddy-cli/
โ”œโ”€โ”€ main.py          # Main program
โ””โ”€โ”€ profile.json      # Created automatically

Step 2: The Basic Structure

Start with imports and profile management:

python
import json
import random
from datetime import datetime

PROFILE_FILE = "profile.json"

QUOTES = [
    "Every expert was once a beginner.",
    "Code is like humor โ€” if you have to explain it, it is bad.",
    "The best way to learn Python: Typing, not just reading!",
    "Errors are not mistakes โ€” they are debugging opportunities.",
    "A program that runs is better than a perfect one that does not exist."
]

def load_profile():
    """Loads the profile from the JSON file or creates a new one."""
    try:
        with open(PROFILE_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {
            "name": "",
            "level": 1,
            "xp": 0,
            "badges": ["PyBuddy User"],
            "tasks": []
        }

def save_profile(profile):
    """Saves the profile as JSON."""
    with open(PROFILE_FILE, "w", encoding="utf-8") as f:
        json.dump(profil, f, indent=2, ensure_ascii=False)

Step 3: The Tool Functions

Each menu feature is implemented as its own function:

python
def show_status(profile):
    """Displays the current profile."""
    print(f"\n{'='*30}")
    print(f"  ๐Ÿ‘ค  {profil['name']}")
    print(f"  ๐Ÿ†  Level {profil['level']}")
    print(f"  โญ  {profil['xp']} XP")
    print(f"  ๐ŸŽ–๏ธ  Badges: {', '.join(profil['badges'])}")
    print(f"{'='*30}\n")

def xp_calculator(profile):
    """Calculates new XP and checks for level-up."""
    basis = int(input("Base XP: "))
    mult = float(input("Multiplier (e.g. 1.5): "))
    bonus = int(input("Bonus-XP: "))
    
    new_xp = int(basis * mult + bonus)
    profil["xp"] += new_xp
    
    # Level-Up alle 500 XP
    new_level = profil["xp"] // 500 + 1
    if new_level > profil["level"]:
        profil["level"] = new_level
        badge = f"Level {new_level}"
        if badge not in profil["badges"]:
            profil["badges"].append(badge)
        print(f"๐ŸŽ‰ Level-Up! You are now level {new_level}!")
    
    print(f"โž• +{new_xp} XP received!")
    print(f"โญ Total: {profil['xp']} XP")

def todo_manager(profil):
    """Manages the to-do list."""
    print("\n๐Ÿ“‹ To-Do Manager")
    print("[1] Add task")
    print("[2] Show tasks")
    print("[3] Complete task")
    wahl = input("Choice: ")
    
    if wahl == "1":
        task = input("New task: ")
        profil["tasks"].append({"text": task, "done": False})
        print("โœ… Added!")
    elif wahl == "2":
        if not profil["tasks"]:
            print("โ„น๏ธ No tasks available.")
        for i, task in enumerate(profil["tasks"], 1):
            status = "โœ“" if task["done"] else "โ–ก"
            print(f"  {i}. {status} {task['text']}")
    elif wahl == "3":
        nr = int(input("Number of completed task: "))
        if 1 <= nr <= len(profil["tasks"]):
            profil["tasks"][nr-1]["done"] = True
            profil["xp"] += 10
            print("โœ… Done! +10 XP")

def zufalls_zitat():
    """Shows a random quote."""
    print(f"\n๐Ÿ’ฌ {random.choice(QUOTES)}\n")

def uhrzeit_anzeigen():
    """Shows the current time."""
    now = datetime.now()
    print(f"๐Ÿ• {now.strftime('%H:%M:%S')} โ€” {now.strftime('%d.%m.%Y')}")

Step 4: The Main Menu

The heart: A while loop that shows the menu and processes the input:

python
def main_menu(profile):
    """Shows the main menu and processes input."""
    while True:
        print(f"\n{'='*30}")
        print(f"  ๐Ÿค–  PyBuddy CLI")
        print(f"  Hello, {profile['name']}!")
        print(f"{'='*30}")
        print("  [1] ๐Ÿ‘ค  Show profile")
        print("  [2] โž•  Calculate XP")
        print("  [3] ๐Ÿ“‹  To-Do Manager")
        print("  [4] ๐Ÿ’ฌ  Random Quote")
        print("  [5] ๐Ÿ•  Time")
        print("  [0] ๐Ÿšช  Exit")
        print(f"{'='*30}")
        
        wahl = input("\nChoose (0-5): ").strip()
        
        if wahl == "0":
            save_profile(profile)
            print(f"๐Ÿ’พ Profile saved. Goodbye, {profil['name']}!")
            break
        elif wahl == "1":
            show_status(profile)
        elif wahl == "2":
            xp_calculator(profile)
        elif wahl == "3":
            todo_manager(profil)
        elif wahl == "4":
            zufalls_zitat()
        elif wahl == "5":
            uhrzeit_anzeigen()
        else:
            print("โš ๏ธ Invalid input. Please enter 0-5.")

Step 5: The Entry Point

Connect everything in the main() function:

python
def main():
    print("๐Ÿค– Welcome to PyBuddy CLI!")
    
    profil = load_profile()
    
    # Erster Start?
    if not profil["name"]:
        profil["name"] = input("What is your name? ").strip()
        print(f"\n๐Ÿ‘‹ Hello {profil['name']}! Nice to have you here.")
        save_profile(profile)
    else:
        print(f"\n๐Ÿ‘‹ Welcome back, {profil['name']}!")
    
    main_menu(profile)

if __name__ == "__main__":
    main()

The Complete Program

Here is the complete code in one file. Copy it to main.py and run it with python main.py:

python
"""
PyBuddy CLI โ€” Abschlussprojekt Python Classic
All 13 chapters united in one interactive assistant.
"""
import json
import random
from datetime import datetime

PROFILE_FILE = "profile.json"

QUOTES = [
    "Every expert was once a beginner.",
    "Code is like humor โ€” if you have to explain it, it is bad.",
    "The best way to learn Python: Typing, not just reading!",
    "Errors are not mistakes โ€” they are debugging opportunities.",
    "A program that runs is better than a perfect one that does not exist."
]

# โ”€โ”€ Profile Management โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def load_profile():
    try:
        with open(PROFILE_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {
            "name": "", "level": 1, "xp": 0,
            "badges": ["PyBuddy User"], "tasks": []
        }

def save_profile(profile):
    with open(PROFILE_FILE, "w", encoding="utf-8") as f:
        json.dump(profil, f, indent=2, ensure_ascii=False)

# โ”€โ”€ Tool-Funktionen โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def show_status(profile):
    print(f"\n{'='*35}")
    print(f"  Profile: {profile['name']}")
    print(f"  Level {profil['level']}  |  {profil['xp']} XP")
    print(f"  Badges: {', '.join(profil['badges'])}")
    print(f"  Tasks: {len(profil['tasks'])}")
    print(f"{'='*35}\n")

def xp_calculator(profile):
    basis = int(input("Base XP: "))
    mult = float(input("Multiplier: "))
    bonus = int(input("Bonus: "))
    new_xp = int(basis * mult + bonus)
    profil["xp"] += new_xp
    new_level = profil["xp"] // 500 + 1
    if new_level > profil["level"]:
        profil["level"] = new_level
        profil["badges"].append(f"Level {new_level}")
        print(f">>> Level-Up! Level {new_level}!")
    print(f">>> +{new_xp} XP | Total: {profil['xp']}")

def todo_manager(profil):
    print("\n--- To-Do Manager ---")
    print("[1] Add  [2] Show  [3] Done")
    wahl = input("Choice: ")
    if wahl == "1":
        profil["tasks"].append({"text": input("Task: "), "done": False})
        print("Added!")
    elif wahl == "2":
        for i, t in enumerate(profil["tasks"], 1):
            s = "[x]" if t["done"] else "[ ]"
            print(f"  {i}. {s} {t['text']}")
    elif wahl == "3":
        nr = int(input("Nummer: "))
        profil["tasks"][nr-1]["done"] = True
        profil["xp"] += 10
        print("Done! +10 XP")

def zufalls_zitat():
    print(f"\n>>> {random.choice(QUOTES)}\n")

def uhrzeit_anzeigen():
    j = datetime.now()
    print(f">>> {j.strftime('%H:%M:%S')} โ€” {j.strftime('%d.%m.%Y')}")

# โ”€โ”€ Main Menu โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def main_menu(profile):
    while True:
        print(f"\n{'='*35}")
        print(f"  PyBuddy CLI โ€” {profil['name']}")
        print(f"{'='*35}")
        print("  [1] Profile    [2] XP Calculator")
        print("  [3] To-Do     [4] Quote")
        print("  [5] Time   [0] Exit")
        print(f"{'='*35}")
        wahl = input("Choose (0-5): ").strip()
        
        if wahl == "0":
            save_profile(profile)
            print(f"Saved. Goodbye, {profil['name']}!")
            break
        elif wahl == "1": show_status(profile)
        elif wahl == "2": xp_calculator(profile)
        elif wahl == "3": todo_manager(profil)
        elif wahl == "4": zufalls_zitat()
        elif wahl == "5": uhrzeit_anzeigen()
        else: print("Invalid. Please enter 0-5.")

# โ”€โ”€ Start โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def main():
    print("=== PyBuddy CLI ===")
    profil = load_profile()
    if not profil["name"]:
        profil["name"] = input("What is your name? ").strip()
        print(f"Hello {profil['name']}!")
        save_profile(profile)
    else:
        print(f"Welcome back, {profil['name']}!")
    main_menu(profile)

if __name__ == "__main__":
    main()

Extension Ideas

Your PyBuddy CLI is finished โ€” but you can expand it further. Here are ideas you can implement with the chapter concepts:

Weather Integration: Fetch current weather with requests (Chapter 11)
Number Guessing: Add the game from Chapter 5 as a menu item
Statistics: Show XP progress as a chart with matplotlib
Password Generator: Create secure passwords with random
Notebook: Save notes as separate JSON files
Multiple Profiles: Manage multiple users with different JSON files
๐Ÿ†

๐Ÿ† Congratulations!

You have completed all 13 chapters and built a complete Python program. That is more than many programmers accomplish in their first month. Your PyBuddy CLI uses variables, conditions, loops, lists, dictionaries, functions, modules and file I/O โ€” all in one project. Show it to your friends, expand it further and above all: Keep coding!