I have this code: import pygame import pygame_gui import sys import requests import difflib import re from datetime import datetime import appointments_lib as appt import psutil import GPUtil import cpuinfo import platform # INIT PYGAME pygame.init() WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("JARVIS") clock = pygame.time.Clock() # PYGAME GUI SETUP manager = pygame_gui.UIManager((WIDTH, HEIGHT)) # UI ELEMENTS terminal = pygame_gui.elements.UITextBox( html_text="", relative_rect=pygame.Rect((10, 10), (780, 550)), manager=manager ) input_line = pygame_gui.elements.UITextEntryLine( relative_rect=pygame.Rect((10, 555), (780, 40)), manager=manager ) input_line.set_text("") # COLOR PALETTE colors = { "default": "#00FFFF", "success": "#00FF00", "error": "#FF3C38", "info": "#FFB627", "user": "#32CD32", } # APPOINTMENTS STORAGE appointments = appt.load_appointments() pending_cancel = None pending_command = None # NATURAL LANGUAGE SUPPORT natural_command_aliases = { "status": ["system status", "how's everything running", "status report", "are all systems nominal"], "shutdown": ["shut down", "power off", "turn off jarvis", "exit"], "help": ["what can you do", "show help", "list commands", "command list", "how can you help"], "weather report": ["what's the weather", "current weather", "how's the weather", "weather right now", "tell me the weather"], "check schedule": ["show my schedule", "do I have any appointments", "what’s on my calendar", "list appointments", "check agenda"], "check schedule today": ["what's on my schedule today", "do i have any appointments today", "show me today's schedule", "what do i have today", "anything planned today", "appointments today", "my schedule today"], } #STATUS OF PC def get_system_status_report(): info = cpuinfo.get_cpu_info() cpu_name = info.get('brand_raw', 'Unknown CPU') cores = psutil.cpu_count(logical=False) threads = psutil.cpu_count(logical=True) cpu_usage = psutil.cpu_percent(interval=1) svmem = psutil.virtual_memory() ram_total = svmem.total / (1024 ** 3) ram_used = svmem.used / (1024 ** 3) ram_percent = svmem.percent try: gpus = GPUtil.getGPUs() gpu_reports = [] for gpu in gpus: gpu_reports.append( f"GPU: {gpu.name} | Load: {gpu.load*100:.1f}% | " f"VRAM: {gpu.memoryUsed:.1f}/{gpu.memoryTotal:.1f} MB | Temp: {gpu.temperature}°C" ) except Exception as e: gpu_reports = ["GPU: Unable to retrieve GPU information."] try: temps = psutil.sensors_temperatures() cpu_temp = None for key in temps: if "coretemp" in key or "cpu_thermal" in key: for entry in temps[key]: if "Package" in entry.label or entry.label == "": cpu_temp = entry.current break if cpu_temp: break temp_line = f"CPU Temperature: {cpu_temp:.1f}°C" if cpu_temp else "CPU Temperature: Unavailable" except Exception: temp_line = "CPU Temperature: Unavailable" system = platform.system() machine = platform.machine() os_version = platform.version() return [ f"System: {system} {machine} | OS Version: {os_version}", f"CPU: {cpu_name} | Cores: {cores} | Threads: {threads} | Usage: {cpu_usage:.1f}%", temp_line, f"RAM Usage: {ram_used:.1f}/{ram_total:.1f} GB ({ram_percent}%)", *gpu_reports, "All systems operational, sir." ] # LOCATION def get_location(): try: response = requests.get("https://ipinfo.io/json") data = response.json() city = data.get("city") loc = data.get("loc") lat, lon = map(float, loc.split(",")) if loc else (0.0, 0.0) return city, lat, lon except Exception as e: print("Location error:", e) return None, 0.0, 0.0 # WEATHER def weather_code_to_desc(code): mapping = { 0: "clear sky", 1: "mainly clear", 2: "partly cloudy", 3: "overcast", 45: "fog", 48: "depositing rime fog", 51: "light drizzle", 53: "moderate drizzle", 55: "dense drizzle", 56: "light freezing drizzle", 57: "dense freezing drizzle", 61: "light rain", 63: "moderate rain", 65: "heavy rain", 66: "light freezing rain", 67: "heavy freezing rain", 71: "light snow", 73: "moderate snow", 75: "heavy snow", 77: "snow grains", 80: "light rain showers", 81: "moderate rain showers", 82: "violent rain showers", 85: "light snow showers", 86: "heavy snow showers", 95: "thunderstorm", 96: "thunderstorm with slight hail", 99: "thunderstorm with heavy hail", } return mapping.get(code, "unknown weather") def get_weather(lat, lon): try: url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}¤t_weather=true" response = requests.get(url) data = response.json() if "current_weather" not in data: return "The weather data is currently unavailable, sir." weather = data["current_weather"] temperature = weather["temperature"] windspeed = weather["windspeed"] weather_code = weather["weathercode"] desc = weather_code_to_desc(weather_code) return ( f"the current weather conditions indicate {desc} " f"with a temperature of {temperature:.1f} degrees Celsius. " f"Wind speed is measured at {windspeed:.1f} kilometers per hour." ) except Exception as e: print("Weather error:", e) return "The weather service is currently unavailable, sir." # NORMALIZATION def normalize(text): return re.sub(r'[^\w\s]', '', text).lower() # TIME & GREETING time = datetime.now() greeting_time = "evening" if 6 <= time.hour < 12: greeting_time = "morning" elif 12 <= time.hour < 18: greeting_time = "afternoon" city, lat, lon = get_location() if city: weather_report = get_weather(lat, lon) else: city = "your area" weather_report = "The weather data is currently unavailable, sir." def build_greeting(): today = appt.get_today_date_str() appts_today = appointments.get(today, []) greet_lines = [ f"Good {greeting_time} sir!", f"It's {time.hour:02}:{time.minute:02}, {weather_report}" ] if appts_today: greet_lines.append("You have the following appointments today:") for appt_item in appts_today: greet_lines.append(f"- {appt_item}") else: greet_lines.append("You have no appointments scheduled for today.") return greet_lines # COMMAND MAP command_map = { "status": "status", "shutdown": "shutdown", "help": "help", "weather report": "weather_rep", "check schedule": "check_schedule", "check schedule today": "check_schedule_today", } # Add natural aliases to command_map def extend_command_map(): for base_cmd, aliases in natural_command_aliases.items(): for phrase in aliases: if phrase not in command_map: command_map[phrase] = command_map[base_cmd] extend_command_map() # TEXT CONTENT init_anim = ["Initializing core systems" + "." * i for i in range(4)] + [ "Checking location.", "Checking location..", f"Location: {city}", '<font color="#00FF00">DONE!</font>' ] startup = [ "Power levels optimal.", "Neural net operational.", "Connection secure.", "Initialization complete.", '<font color="#00FF00">J.A.R.V.I.S is now online!</font>' ] sorry = ["No need to apologize sir."] oweu_welcome = ["Don't worry sir, I am happy to help."] welcome = ["You're very welcome sir! I am at your service. If I can provide assistance, please ask."] greeting = build_greeting() status = get_system_status_report() shutdown = ["SHUTTING DOWN..."] help = [ "AVAILABLE COMMANDS:", "STATUS OF ALL SYSTEMS - 'status'", "SHUTDOWN AI SYSTEM - 'shutdown'", "SHOW ALL AVAILABLE COMMANDS - 'help'", "SHOW WEATHER REPORT - 'weather report'", "ADD APPOINTMENT - 'add appointment YYYY-MM-DD description'", "CANCEL APPOINTMENT - 'cancel appointment YYYY-MM-DD description'", "VIEW SCHEDULE - 'check schedule'", "VIEW TODAY'S SCHEDULE - 'check schedule today'", ] weather_rep = [f"{weather_report}".capitalize()] error = ["ERROR - COMMAND UNKNOWN"] schedule_lines = [] displayed = [] last_update = 0 defdelay = 2000 index = 0 phase = "init" def show_text(text, delay=defdelay, stage="", loop=False, color="default"): global current_time, last_update, index, phase, displayed color_hex = colors.get(color, colors["default"]) if index == 0: input_line.disable() if current_time - last_update > delay and index < len(text): line = f'<font color="{color_hex}">{text[index]}</font>' if loop: terminal.set_text(line) else: displayed.append(line) terminal.set_text("<br>".join(displayed[-100:])) index += 1 last_update = current_time input_line.set_text("") if index >= len(text): index = 0 phase = f"{stage}" input_line.enable() input_line.focus() # MAIN LOOP run = True while run: time_delta = clock.tick(60) / 1000 current_time = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame_gui.UI_TEXT_ENTRY_FINISHED and event.ui_element == input_line and event.text != "": user_command = event.text.strip() displayed.append(f'<font color="{colors["user"]}">> {user_command}</font>') cmd = normalize(user_command) if pending_cancel: if cmd in ["yes", "y"]: date_str, appt_text = pending_cancel if appt.cancel_appointment(appointments, date_str, appt_text): displayed.append(f'<font color="{colors["success"]}">Appointment on {date_str} cancelled.</font>') else: displayed.append(f'<font color="{colors["error"]}">No matching appointment found for {date_str}.</font>') pending_cancel = None elif cmd in ["no", "n"]: displayed.append(f'<font color="{colors["error"]}">Cancellation aborted.</font>') pending_cancel = None else: displayed.append(f'<font color="{colors["default"]}">Please respond with only yes or no, sir.</font>') terminal.set_text("<br>".join(displayed[-100:])) input_line.set_text("") continue elif pending_command: if cmd in ["yes", "y"]: phase = command_map[pending_command] pending_command = None elif cmd in ["no", "n"]: displayed.append(f'<font color="{colors["error"]}">Command aborted.</font>') pending_command = None else: displayed.append(f'<font color="{colors["default"]}">Please respond with only yes or no, sir.</font>') terminal.set_text("<br>".join(displayed[-100:])) input_line.set_text("") continue elif cmd.startswith("add appointment"): parts = user_command.split(' ', 3) if len(parts) < 4: displayed.append(f'<font color="{colors["error"]}">Invalid format. Use: add appointment YYYY-MM-DD description</font>') else: date_str = parts[2] appt_text = parts[3] try: datetime.strptime(date_str, "%Y-%m-%d") appt.add_appointment(appointments, date_str, appt_text) displayed.append(f'<font color="{colors["success"]}">Appointment added for {date_str}.</font>') except ValueError: displayed.append(f'<font color="{colors["error"]}">Invalid date format. Use YYYY-MM-DD.</font>') elif cmd.startswith("cancel appointment"): parts = user_command.split(' ', 3) if len(parts) < 4: displayed.append(f'<font color="{colors["error"]}">Invalid format. Use: cancel appointment YYYY-MM-DD description</font>') else: date_str = parts[2] appt_text = parts[3] if date_str in appointments: best_match = difflib.get_close_matches(appt_text, appointments[date_str], n=1, cutoff=0.6) if best_match: displayed.append(f'<font color="{colors["default"]}">Did you mean to cancel "{best_match[0]}" on {date_str}?</font>') pending_cancel = (date_str, best_match[0]) else: displayed.append(f'<font color="{colors["error"]}">No similar appointment found on {date_str}.</font>') else: displayed.append(f'<font color="{colors["error"]}">No appointments found on {date_str}.</font>') elif cmd.startswith(("thank", "i thank", "i appreciate", "appreciate", "much obliged")): phase = "welcome" elif cmd.startswith(("i owe you", "i'm in debt", "i am in debt", "i will make it up", "i'll make it up", "im in debt")): phase = "oweu_welcome" elif cmd.startswith(("sorry", "apologies", "i apologize", "pardon", "i'm sorry", "i sorry")): phase = "sorry" elif cmd in command_map: phase = command_map[cmd] else: match = difflib.get_close_matches(cmd, command_map.keys(), n=1, cutoff=0.6) if match: displayed.append(f'<font color="{colors["default"]}">Did you mean "{match[0]}"?</font>') pending_command = match[0] else: phase = "error" terminal.set_text("<br>".join(displayed[-100:])) input_line.set_text("") manager.process_events(event) # PHASE-BASED RESPONSE if phase == "init": show_text(init_anim, 350, "startup", True, "default") elif phase == "startup": show_text(startup, defdelay, "greet", True, "default") elif phase == "greet": greeting = build_greeting() show_text(greeting, color="default") elif phase == "error": show_text(error, 0, color="error") elif phase == "status": show_text(status, color="default") elif phase == "help": show_text(help, 0, color="info") elif phase == "shutdown": show_text(shutdown, color="default") run = False elif phase == "weather_rep": show_text(weather_rep, color="default") elif phase == "check_schedule": schedule_lines = appt.get_schedule_lines(appointments) show_text(schedule_lines, color="default") elif phase == "check_schedule_today": today = appt.get_today_date_str() schedule_lines = appointments.get(today, []) or ["You have no appointments scheduled for today, sir."] show_text(["Today's appointments:"] + [f"- {a}" for a in schedule_lines] if schedule_lines else schedule_lines, color="default") elif phase == "welcome": show_text(welcome, color="default") elif phase == "oweu_welcome": show_text(oweu_welcome, color="default") elif phase == "sorry": show_text(sorry, color="default") screen.fill((0, 0, 0)) manager.draw_ui(screen) manager.update(time_delta) pygame.display.update() pygame.time.wait(700) pygame.quit() sys.exit() And when the terminal gets crowded and the scroll bar appears, it's default position is to stay up, and only moves down when the user moves it downwards. But if it receives any input or output, it moves back up. I have already tried using chat gpt and copilot from VSC to fix this issue, I needed this ready asap and I'm new with pygame_gui, so I don't really know how to fix this issue. I wanted the scrollbar to stay permanently down, when it receives inputs and outputs, and only move up if the user chooses to (either by scrolling or dragging the scrollbar) Continue reading...