""" Module: ui.py ------------- Obsahuje interaktivní rozhraní Robovojtíka založené na knihovně curses. """ import curses import time import threading import logging import api_interface import shell_functions logger = logging.getLogger("robovojtik.ui") # Definujeme globální proměnnou automode zde automode = False def main_curses(stdscr): curses.start_color() curses.use_default_colors() curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) # Hlavička curses.init_pair(2, curses.COLOR_WHITE, -1) # Chat curses.init_pair(3, curses.COLOR_GREEN, -1) # Výstup curses.init_pair(4, curses.COLOR_YELLOW, -1) # Vstup curses.init_pair(5, curses.COLOR_CYAN, -1) # Spinner curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_WHITE) # Oddělovač curses.curs_set(1) stdscr.nodelay(False) stdscr.clear() height, width = stdscr.getmaxyx() header_height = 3 prompt_height = 2 left_width = width // 2 right_width = width - left_width - 1 # oddělovač = 1 sloupec chat_height = height - header_height - prompt_height header_win = curses.newwin(header_height, left_width, 0, 0) chat_win = curses.newwin(chat_height, left_width, header_height, 0) prompt_win = curses.newwin(prompt_height, width, height - prompt_height, 0) output_win = curses.newwin(height - prompt_height, right_width, 0, left_width + 1) divider_win = curses.newwin(height - prompt_height, 1, 0, left_width) header_win.bkgd(' ', curses.color_pair(1)) chat_win.bkgd(' ', curses.color_pair(2)) prompt_win.bkgd(' ', curses.color_pair(4)) output_win.bkgd(' ', curses.color_pair(3)) divider_win.bkgd(' ', curses.color_pair(6)) d_height, _ = divider_win.getmaxyx() for y in range(d_height): try: divider_win.addch(y, 0, curses.ACS_VLINE) except curses.error: pass divider_win.refresh() header_text = [ "Vítejte v Robovojtikovi!", "Zadejte dotaz, příkaz (prefix 'cmd:'), 'automat',", "nebo napiš 'napiš mi skript, ...' pro generování skriptu.", "Pro ukončení zadejte 'vypni' nebo 'exit'." ] max_chars = max(0, left_width - 2) for idx, line in enumerate(header_text): try: header_win.addnstr(idx, 1, line, max_chars) except curses.error: pass header_win.refresh() chat_win.scrollok(True) output_win.scrollok(True) prompt_win.scrollok(True) output_win.box() output_win.refresh() spinner_chars = ["|", "/", "-", "\\"] def spinner_func(ch): mid_x = left_width // 2 - 5 header_win.addnstr(1, mid_x, f"Čekám... {ch}", left_width - mid_x - 1, curses.color_pair(5) | curses.A_BOLD) header_win.refresh() chat_history = [] def add_to_chat(text): chat_history.append(text) chat_win.addstr(text + "\n") chat_win.refresh() add_to_chat("Historie chatu:") while True: prompt_win.erase() prompt_win.addstr(">> ", curses.A_BOLD) prompt_win.refresh() curses.echo() try: user_input = prompt_win.getstr().decode("utf-8").strip() except Exception: continue curses.noecho() if not user_input: continue add_to_chat("Ty: " + user_input) if user_input.lower() in ["vypni", "exit"]: add_to_chat("Ukončuji Robovojtíka...") time.sleep(1) break if user_input.lower() == "automat": global automode automode = not automode stav = "zapnut" if automode else "vypnut" add_to_chat(f"Automód byl nyní {stav}.") continue if user_input.lower().startswith("skript:"): try: _, rest = user_input.split("skript:", 1) parts = rest.split(";", 1) if len(parts) < 2: add_to_chat("Pro vytvoření skriptu uveďte název a popis oddělené středníkem.") continue file_name = parts[0].strip() description = parts[1].strip() add_to_chat(f"Vytvářím skript '{file_name}' na základě popisu: {description}") generated_content = api_interface.posli_dotaz_do_assistenta("Vygeneruj skript podle popisu: " + description) add_to_chat("Generovaný obsah skriptu:\n" + generated_content) result = shell_functions.vytvor_skript(file_name, generated_content) add_to_chat(result) except Exception as e: add_to_chat(f"Chyba při vytváření skriptu: {str(e)}") continue if user_input.startswith("cmd:"): command = user_input[4:].strip() add_to_chat(f"Rozpoznán přímý příkaz: {command}") if not automode: prompt_win.erase() prompt_win.addstr("Spustit tento příkaz? (y/n): ", curses.A_BOLD) prompt_win.refresh() potvrzeni = prompt_win.getstr().decode("utf-8").strip().lower() add_to_chat("Ty: " + potvrzeni) if potvrzeni != "y": add_to_chat("Příkaz nebyl spuštěn.") continue output, response = shell_functions.run_command_locally_and_report(command, api_interface) output_win.erase() output_win.addstr(1, 1, output) output_win.box() output_win.refresh() add_to_chat("Robovojtík odpovídá:\n" + response) continue assistant_response = api_interface.volani_asistenta(user_input, spinner_func=spinner_func) add_to_chat("Robovojtík odpovídá:\n" + assistant_response) if assistant_response.strip().lower().startswith("navrhovaný příkaz:"): lines = assistant_response.splitlines() proposal_line = lines[0] navrhovany_prikaz = proposal_line[len("Navrhovaný příkaz:"):].strip() add_to_chat(f"Navrhovaný příkaz: {navrhovany_prikaz}") if not automode: prompt_win.erase() prompt_win.addstr("Spustit tento příkaz? (y/n): ", curses.A_BOLD) prompt_win.refresh() potvrzeni = prompt_win.getstr().decode("utf-8").strip().lower() add_to_chat("Ty: " + potvrzeni) if potvrzeni != "y": add_to_chat("Příkaz nebyl spuštěn.") continue output, response = shell_functions.run_command_locally_and_report(navrhovany_prikaz, api_interface) output_win.erase() output_win.addstr(1, 1, output) output_win.box() output_win.refresh() add_to_chat("Robovojtík odpovídá:\n" + response) prompt_win.erase() prompt_win.refresh() def main_ui(): curses.wrapper(main_curses)