Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00052.parquet:38410

adfbe076106a122fc821aec0
turn 1/1o1-preview-2024-09-12EnglishGermany6225 words
degenerate_repetitionAbsentFinal dense release
USER
Split the class TableManager: into three classes to improve maintainability and readability. Python Code: import ctypes
import csv
import json
import re
import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox, simpledialog, ttk
from typing import Any, Optional

from tksheet import Sheet


def set_dpi_awareness():
    """Enable DPI awareness for high DPI settings."""
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    except Exception as e:
        print(f"Error setting DPI awareness: {e}")

def create_frame(parent: tk.Widget, width: Optional[int] = None, bg: str = "SystemButtonFace") -> tk.Frame:
    """Creates a frame with specified width and background color."""
    frame = tk.Frame(parent, width=width, bg=bg, bd=0, relief="flat")
    if width:
        frame.config(width=width)
    return frame

def custom_filter_design(
    master,
    style: ttk.Style,
    headers=None,
    filter_types=None,
    filter_font=None,
    filter_combobox_font=None,
    colors=None,
):
    """Creates a custom filter frame with all components."""
    filter_frame = ttk.Frame(master, style="Custom.TFrame")

    # Configure styles
    style.configure(
        "Custom.TFrame",
        background=colors["background"],
        relief="flat",
        borderwidth=0,
    )
    style.configure(
        "TCombobox",
        relief="flat",
        borderwidth=0,
        background=colors["background"],
        fieldbackground=colors["background"],
    )
    style.map(
        "TCombobox",
        fieldbackground=[("readonly", colors["background"])],
        background=[("readonly", colors["background"])],
    )
    style.configure(
        "TEntry",
        relief="flat",
        borderwidth=0,
        background=colors["background"],
    )
    style.configure("Line.TFrame", background=colors["filter_line"])

    # Create widgets
    header_combobox = ttk.Combobox(
        filter_frame,
        values=headers,
        width=15,
        font=filter_combobox_font,
        state="readonly",
    )
    filtertype_combobox = ttk.Combobox(
        filter_frame,
        values=filter_types,
        width=15,
        font=filter_combobox_font,
        state="readonly",
    )
    filter_entry = ttk.Entry(filter_frame, font=filter_font)
    underline = ttk.Frame(filter_frame, height=1, style="Line.TFrame")

    # Layout widgets
    header_combobox.grid(row=0, column=0, padx=(0, 30), pady=2, sticky="ew")
    filtertype_combobox.grid(row=0, column=1, padx=2, pady=2, sticky="ew")
    filter_entry.grid(
        row=1, column=0, columnspan=2, padx=2, pady=(2, 0), sticky="ew"
    )
    underline.grid(row=2, column=0, columnspan=2, sticky="ew", pady=(0, 2))

    # Prevent text selection in comboboxes
    for combobox in (header_combobox, filtertype_combobox):
        combobox.bind("<FocusIn>", lambda event: event.widget.selection_clear())

    # Configure column weights
    filter_frame.columnconfigure((0, 1), weight=1)

    # Ensure the underline doesn't resize vertically
    underline.pack_propagate(False)

    return (
        filter_frame,
        header_combobox,
        filtertype_combobox,
        filter_entry,
    )


def custom_scrollbar_design(style: ttk.Style, colors=None):
    """Configure custom scrollbar style."""
    style.configure(
        "Custom.Vertical.TScrollbar",
        troughcolor=colors["scrollbar_trough"],
        background=colors["scrollbar_background"],
        borderwidth=0,
        arrowcolor=colors["scrollbar_arrow"],
    )
    style.map(
        "Custom.Vertical.TScrollbar",
        background=[("active", colors["scrollbar_active"])],
    )
    style.layout(
        "Custom.Vertical.TScrollbar",
        [
            (
                "Vertical.Scrollbar.trough",
                {
                    "children": [
                        (
                            "Vertical.Scrollbar.thumb",
                            {"expand": "1", "sticky": "ns"},
                        )
                    ],
                    "sticky": "ns",
                },
            )
        ],
    )


class TableApp:
    """Main application controller for database table visualization."""

    def __init__(self, root: tk.Tk):
        """Initialize the TableApp with basic configuration and UI setup."""
        self._initialize_root(root)
        self._initialize_configurations()
        self._initialize_core_components()
        self._setup_ui_components()
        self._load_initial_data()

    def _initialize_root(self, root: tk.Tk):
        """Set up the root window properties."""
        self.root = root
        self.root.title("Database")
        self.root.geometry("1920x1080")
        self.root.minsize(1435, 910)

    def _initialize_configurations(self):
        """Initialize all configurations including dimensions, fonts, colors, and style."""
        self._set_dimensions()
        self._set_fonts()
        self._set_colors()
        self._set_style()

    def _set_dimensions(self):
        """Define application dimensions."""
        self.dimensions = {
            "sidebar_width": 400,
            "spacer_frame_width": 100,
            "header_height": 190,
            "separator_height": 1
        }

    def _set_fonts(self):
        """Define application fonts."""
        self.fonts = {
            "text": ("Literata", 12),
            "tksheet": ("Literata", 12, "normal"),
            "header_info": ("Literata", 10),
            "filter": ("Literata", 12),
            "filter_combobox": ("Literata", 8)
        }

    def _set_colors(self):
        """Define application colors."""
        self.colors = {
            "text": "#333333",
            "background": "#FFFFFF",
            "sidebar": "#F7F8FC",
            "button": "#F7F8FC",
            "button_selected": "#EAEDEF",
            "separator": "#333333",
            "header_info": "#999999",
            "scrollbar_trough": "#F7F8FC",
            "scrollbar_background": "#c0c1c4",
            "scrollbar_arrow": "#333333",
            "scrollbar_active": "#878789",
            "filter_line": "#00bcf0"
        }

    def _set_style(self):
        """Initialize and configure the application style."""
        self.style = ttk.Style()
        self.style.theme_use("default")

    def _initialize_core_components(self):
        """Initialize core application components and state variables."""
        self.current_table_name: str | None = None
        self.current_sheet: Sheet | None = None
        self.displayed_row_indices: list[int] = []
        
        self.data_manager = DataManager(self)
        self.table_manager = TableManager(self)

    def _setup_ui_components(self):
        """Set up all UI components and their layout."""
        self._configure_grid()
        self._create_main_components()
        self._create_auxiliary_frames()

    def _configure_grid(self):
        """Configure the root window grid layout."""
        self.root.grid_rowconfigure(0, weight=0)
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=0)
        self.root.grid_columnconfigure(1, weight=0, 
                                     minsize=self.dimensions["spacer_frame_width"])
        self.root.grid_columnconfigure(2, weight=3)

    def _create_main_components(self):
        """Create main UI components."""
        self.sidebar = Sidebar(self.root, self)
        self.header = Header(self.root, self)
        self.filter_controls = FilterControls(self.header.lower_header_frame, self)

    def _create_auxiliary_frames(self):
        """Create auxiliary frames for layout purposes."""
        self._create_spacer_frame()
        self._create_table_frame()

    def _create_spacer_frame(self):
        """Create and configure the spacer frame."""
        spacer = create_frame(
            parent=self.root,
            width=self.dimensions["spacer_frame_width"],
            bg=self.colors["background"]
        )
        spacer.grid(row=1, column=1, sticky="nsew")
        spacer.grid_propagate(False)

    def _create_table_frame(self):
        """Create and configure the main table frame."""
        self.table_frame = create_frame(
            parent=self.root,
            width=None,
            bg=self.colors["background"]
        )
        self.table_frame.grid(row=1, column=2, sticky="nsew")
        self.table_frame.grid_rowconfigure(0, weight=1)
        self.table_frame.grid_columnconfigure(0, weight=1)

    def _load_initial_data(self):
        """Load initial application data."""
        self.data_manager.load_tables()

    # Public methods
    def load_selected_table(self, table_name: str):
        """Load and display the selected table."""
        self.table_manager.load_selected_table(table_name)

    def refresh_table(self):
        """Refresh the currently displayed table."""
        if self.current_table_name:
            self.load_selected_table(self.current_table_name)

    def apply_filter(self):
        """Apply the current filter to the table."""
        self.filter_controls.apply_filter()


class DataManager:
    """Handles data persistence, loading, and saving."""

    def __init__(self, app: TableApp):
        self.app = app
        self.save_file_path = Path(__file__).parent / "Data.json"
        self.tables_data: dict[str, dict] = {}
        self.headers: dict[str, list[str]] = {}

    def load_tables(self):
        """Load tables from file."""
        if not self.save_file_path.exists():
            return
        try:
            with self.save_file_path.open("r", encoding="utf-8") as file:
                all_data = json.load(file)
        except Exception as e:
            messagebox.showerror("Load Error", f"Failed to load tables: {e}")
            return
        for table_name, data in all_data.items():
            if not isinstance(data, list) or not data:
                continue
            headers, table_data = data[0], data[1:]
            self.headers[table_name] = headers
            self.tables_data[table_name] = {"headers": headers, "data": table_data}
            # Inform Sidebar to create table label
            self.app.sidebar.create_table_label(table_name)
        self.app.sidebar.sort_table_labels()

    def save_data(self):
        """Save all tables data."""
        all_data = {}
        for table_name, table_info in self.tables_data.items():
            all_data[table_name] = [table_info["headers"]] + table_info["data"]
        try:
            with self.save_file_path.open("w", encoding="utf-8") as file:
                json.dump(all_data, file, indent=4)
        except Exception as e:
            print(f"Error saving data: {e}")


class TableManager:
    """Deals with table operations like creation, deletion, loading, and saving."""

    def __init__(self, app: TableApp):
        self.app = app

    def create_new_table(self):
        """Create a new table."""
        existing_numbers = [
            int(name.split(" ")[1])
            for name in self.app.data_manager.tables_data
            if name.startswith("Table ") and name.split(" ")[1].isdigit()
        ]
        next_number = max(existing_numbers, default=0) + 1
        table_name = f"Table {next_number}"
        self.add_table(table_name)
        self.load_selected_table(table_name)

    def add_table(
        self,
        table_name: str,
        data: list[list[str]] | None = None,
        headers: Optional[list[str]] = None,
    ):
        """Add a new table."""
        if headers:
            self.app.data_manager.headers[table_name] = headers
        else:
            default_headers = [
                "Column 1",
                "Column 2",
                "Column 3",
                "Column 4",
                "Column 5",
            ]
            self.app.data_manager.headers[table_name] = default_headers
        self.app.data_manager.tables_data[table_name] = {
            "headers": self.app.data_manager.headers[table_name],
            "data": data
            or [
                ["" for _ in range(len(self.app.data_manager.headers[table_name]))]
                for _ in range(10)
            ],
        }
        self.app.sidebar.create_table_label(table_name)
        self.app.data_manager.save_data()

    def load_selected_table(self, table_name: str):
        """Display selected table."""
        if self.app.current_sheet:
            self.app.current_sheet.pack_forget()
            self.app.current_sheet.destroy()
            self.app.current_sheet = None
        if self.app.sidebar.selected_table_label:
            try:
                self.app.sidebar.selected_table_label.config(
                    bg=self.app.colors["button"]
                )
            except tk.TclError:
                self.app.sidebar.selected_table_label = None

        if table_name not in self.app.data_manager.tables_data:
            messagebox.showerror("Error", f"Table '{table_name}' does not exist.")
            self.app.current_table_name = None
            self.app.sidebar.selected_table_label = None
            return

        table_info = self.app.data_manager.tables_data[table_name]
        headers = table_info["headers"]
        data = table_info["data"]
        try:
            sheet = Sheet(
                self.app.table_frame,
                data=data,
                show_table=True,
                headers=headers,
                font=self.app.fonts["tksheet"],
                header_font=self.app.fonts["tksheet"],
                auto_resize_columns=True,
            )
            sheet.set_options(
                table_fg=self.app.colors["text"], header_fg=self.app.colors["text"]
            )
            sheet.enable_bindings()
            sheet.extra_bindings(
                [
                    ("end_edit_cell", self.on_cell_edit),
                    ("end_delete_columns", self.on_columns_deleted),
                ]
            )
            sheet.pack(expand=True, fill="both")
            self.app.current_sheet = sheet
            self.app.current_table_name = table_name

            if self.app.header.table_name_label:
                self.app.header.table_name_label.config(text=self.app.current_table_name)
            else:
                self.app.header.table_name_label = tk.Label(
                    self.app.root,
                    text=self.app.current_table_name,
                    bg=self.app.colors["background"],
                    fg=self.app.colors["text"],
                    font=self.app.fonts["header_info"],
                )
                self.app.header.table_name_label.grid(
                    row=0, column=0, padx=(60, 10), pady=(5, 0), sticky="nw"
                )

            label = self.app.sidebar.table_labels.get(table_name)
            if label:
                self.app.sidebar.selected_table_label = label
                try:
                    self.app.sidebar.selected_table_label.config(
                        bg=self.app.colors["button_selected"]
                    )
                except tk.TclError:
                    self.app.sidebar.selected_table_label = None
                    messagebox.showerror(
                        "Error", f"Failed to update the label for '{table_name}'."
                    )
            else:
                self.app.sidebar.selected_table_label = None
                messagebox.showerror("Error", f"Label for '{table_name}' not found.")

            self.app.filter_controls.filter_header_var.set("All")
            self.app.filter_controls.filter_header_dropdown["values"] = ["All"] + headers

            self.app.filter_controls.filter_option_var.set("contains")
            self.app.filter_controls.update_filter_text_state()

            self.app.apply_filter()
        except Exception as e:
            messagebox.showerror(
                "Sheet Error", f"Failed to load table '{table_name}': {e}"
            )
            self.app.current_table_name = None
            self.app.sidebar.selected_table_label = None

    def on_cell_edit(self, event=None):
        """Handle cell edits."""
        if self.app.current_table_name and self.app.current_sheet:
            sheet_data = self.app.current_sheet.get_sheet_data()
            for idx, row in enumerate(sheet_data):
                if idx < len(self.app.displayed_row_indices):
                    data_idx = self.app.displayed_row_indices[idx]
                    self.app.data_manager.tables_data[self.app.current_table_name][
                        "data"
                    ][data_idx] = row
                else:
                    # Handle new rows by appending to the underlying data
                    self.app.data_manager.tables_data[self.app.current_table_name][
                        "data"
                    ].append(row)
            self.app.data_manager.save_data()

    def on_columns_deleted(self, event):
        """Handle column deletion and update filter headers."""
        if not self.app.current_table_name or not self.app.current_sheet:
            return
        new_headers = self.app.current_sheet.headers()
        self.app.data_manager.headers[self.app.current_table_name] = new_headers
        self.app.filter_controls.filter_header_dropdown["values"] = ["All"] + new_headers
        self.app.filter_controls.filter_header_var.set("All")
        self.app.filter_controls.filter_option_var.set("contains")
        self.app.filter_controls.filter_text_var.set("")
        self.app.filter_controls.filter_text_entry.config(state="normal")
        self.app.apply_filter()

    def import_file(self):
        """Import table from file."""
        file_path = filedialog.askopenfilename(
            title="Import File",
            filetypes=[
                ("All Supported Files", "*.json *.csv"),
                ("JSON files", "*.json"),
                ("CSV files", "*.csv"),
            ],
        )
        if not file_path:
            return
        try:
            if file_path.endswith(".csv"):
                with open(file_path, newline="", encoding="utf-8") as csvfile:
                    data = list(csv.reader(csvfile))
            elif file_path.endswith(".json"):
                with open(file_path, "r", encoding="utf-8") as jsonfile:
                    data = json.load(jsonfile)
            else:
                raise ValueError("Unsupported file format.")
            if (
                not data
                or not isinstance(data, list)
                or not all(isinstance(row, list) for row in data)
            ):
                raise ValueError("Invalid data format in the file.")
            headers, table_data = data[0], data[1:]
            self.add_table_from_data(file_path, headers, table_data)
        except Exception as e:
            messagebox.showerror("File Import Error", str(e))

    def add_table_from_data(
        self, file_path: str, headers: list[str], table_data: list[list[str]]
    ):
        """Add a table from file data."""
        table_name = Path(file_path).stem
        table_name = self.ensure_unique_table_name(table_name)
        self.add_table(table_name, data=table_data, headers=headers)
        self.load_selected_table(table_name)
        self.app.data_manager.save_data()

    def ensure_unique_table_name(self, table_name: str) -> str:
        """Ensure table name is unique."""
        original_name = table_name
        counter = 1
        while table_name in self.app.data_manager.tables_data:
            table_name = f"{original_name} (New {counter})"
            counter += 1
        return table_name

    def export_table(self):
        """Export current table to file."""
        if (
            not self.app.current_table_name
            or self.app.current_table_name not in self.app.data_manager.tables_data
        ):
            messagebox.showwarning(
                "No Table Selected", "Please select a table to export."
            )
            return
        file_path = filedialog.asksaveasfilename(
            title="Export File",
            defaultextension=".json",
            filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")],
            initialfile=self.app.current_table_name,
        )
        if not file_path:
            return
        try:
            data = [
                self.app.data_manager.headers[self.app.current_table_name]
            ] + self.app.data_manager.tables_data[self.app.current_table_name]["data"]
            if file_path.endswith(".csv"):
                self.save_table_data(file_path, data, "csv")
            elif file_path.endswith(".json"):
                with open(file_path, "w", encoding="utf-8") as file:
                    json.dump(data, file, indent=4)
            else:
                raise ValueError("Unsupported file format.")
            self.app.data_manager.save_data()
            messagebox.showinfo(
                "Export Successful",
                f"Table '{self.app.current_table_name}' has been exported successfully.",
            )
        except Exception as e:
            messagebox.showerror(
                "Export Failed", f"An error occurred during export: {e}"
            )

    def save_table_data(self, file_path: str, data: list[list[str]], format: str):
        """Save table data in specified format."""
        match format:
            case "csv":
                with open(file_path, "w", newline="", encoding="utf-8") as file:
                    csv.writer(file).writerows(data)
            case "json":
                with open(file_path, "w", encoding="utf-8") as file:
                    json.dump(data, file, indent=4)
            case _:
                raise ValueError("Unsupported file format.")

    def delete_table(self):
        """Delete selected table."""
        if (
            not self.app.current_table_name
            or self.app.current_table_name not in self.app.data_manager.tables_data
        ):
            messagebox.showwarning(
                "No Table Selected", "Please select a valid table to delete."
            )
            return
        if messagebox.askyesno(
            "Delete Table",
            f"Are you sure you want to delete the table '{self.app.current_table_name}'?",
        ):
            self.remove_table(self.app.current_table_name)

    def remove_table(self, table_name: str):
        """Remove a table."""
        if self.app.current_table_name == table_name and self.app.current_sheet:
            self.app.current_sheet.destroy()
            self.app.current_sheet = None
        label = self.app.sidebar.table_labels.get(table_name)
        if label:
            label.destroy()
        if table_name in self.app.data_manager.tables_data:
            del self.app.data_manager.tables_data[table_name]
        if table_name in self.app.data_manager.headers:
            del self.app.data_manager.headers[table_name]
        if table_name in self.app.sidebar.table_labels:
            del self.app.sidebar.table_labels[table_name]
        self.app.current_table_name = None
        self.app.sidebar.selected_table_label = None
        self.app.data_manager.save_data()
        self.app.sidebar.sort_table_labels()

    def rename_headers(self):
        """Rename table headers."""
        if not self.app.current_table_name:
            messagebox.showwarning(
                "No Table Selected", "Please select a table to rename headers."
            )
            return
        current_headers = self.app.data_manager.headers[self.app.current_table_name]
        new_headers = simpledialog.askstring(
            "Rename Headers",
            "Enter new headers (comma-separated):",
            initialvalue=", ".join(current_headers),
        )
        if new_headers:
            header_list = [header.strip() for header in new_headers.split(",")]
            if not header_list:
                messagebox.showerror("Invalid Headers", "Header list cannot be empty.")
                return
            self.app.data_manager.headers[self.app.current_table_name] = header_list
            self.app.data_manager.tables_data[self.app.current_table_name][
                "headers"
            ] = header_list
            if self.app.current_sheet:
                try:
                    self.app.current_sheet.headers(header_list)
                except tk.TclError as e:
                    messagebox.showerror("Error", f"Failed to rename headers: {e}")

            self.app.filter_controls.filter_header_var.set("All")
            self.app.filter_controls.filter_header_dropdown["values"] = [
                "All"
            ] + header_list
            self.app.apply_filter()

            self.app.data_manager.save_data()

    def begin_rename(self, table_name: str):
        """Start renaming a table."""
        if table_name not in self.app.sidebar.table_labels:
            messagebox.showerror("Error", f"Table '{table_name}' not found.")
            return
        label = self.app.sidebar.table_labels[table_name]
        self.cancel_rename()
        self.app.sidebar.rename_entry = tk.Entry(
            self.app.sidebar.table_labels_frame,
            bg=label.cget("bg"),
            fg=self.app.colors["text"],
            relief="flat",
        )
        self.app.sidebar.rename_entry.insert(0, table_name)
        self.app.sidebar.rename_entry.place(
            x=label.winfo_x(),
            y=label.winfo_y(),
            width=label.winfo_width(),
            height=label.winfo_height(),
        )
        self.app.sidebar.rename_entry.focus()
        self.app.sidebar.rename_entry.select_range(0, tk.END)
        self.app.sidebar.rename_entry.bind(
            "<Return>", lambda event: self.end_rename(table_name)
        )
        self.app.sidebar.rename_entry.bind("<FocusOut>", lambda event: self.cancel_rename())

    def end_rename(self, old_name: str):
        """Finalize table renaming."""
        new_name = self.app.sidebar.rename_entry.get().strip()
        if not new_name:
            messagebox.showerror("Invalid Name", "Table name cannot be empty.")
            self.app.sidebar.rename_entry.focus_set()
            return
        if new_name in self.app.data_manager.tables_data and new_name != old_name:
            messagebox.showerror(
                "Duplicate Name", f"A table named '{new_name}' already exists."
            )
            self.app.sidebar.rename_entry.focus_set()
            return
        if new_name != old_name:
            self.update_table_name(old_name, new_name)
            self.load_selected_table(new_name)
        self.cancel_rename()

    def update_table_name(self, old_name: str, new_name: str):
        """Update table name and resources."""
        self.app.data_manager.tables_data[new_name] = self.app.data_manager.tables_data.pop(
            old_name
        )
        self.app.data_manager.headers[new_name] = self.app.data_manager.headers.pop(
            old_name
        )
        label = self.app.sidebar.table_labels.pop(old_name)
        label.config(text=new_name)
        label.bind(
            "<Button-1>", lambda event: self.load_selected_table(new_name)
        )
        label.bind(
            "<Double-1>", lambda event: self.begin_rename(new_name)
        )
        self.app.sidebar.table_labels[new_name] = label
        if self.app.sidebar.selected_table_label == label:
            try:
                label.config(bg=self.app.colors["button_selected"])
            except tk.TclError:
                pass
        self.app.data_manager.save_data()
        self.app.sidebar.sort_table_labels()

    def cancel_rename(self):
        """Cancel rename operation."""
        if self.app.sidebar.rename_entry:
            self.app.sidebar.rename_entry.destroy()
            self.app.sidebar.rename_entry = None


class Sidebar:
    """Handles all sidebar-related UI and interactions."""

    def __init__(self, root: tk.Tk, app: TableApp):
        self.root = root
        self.app = app
        self.colors = app.colors
        self.fonts = app.fonts
        self.dimensions = app.dimensions
        self.style = app.style

        # Initialize variables
        self.table_labels_frame: Optional[tk.Frame] = None
        self.table_labels: dict[str, tk.Label] = {}
        self.selected_table_label: Optional[tk.Label] = None
        self.rename_entry: Optional[tk.Entry] = None

        self.create_sidebar()

    def create_sidebar(self):
        """Create the sidebar UI components."""
        self.sidebar_frame = create_frame(
            parent=self.root,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        self.sidebar_frame.grid(row=0, column=0, rowspan=2, sticky="ns")
        self.sidebar_frame.grid_propagate(False)
        self.sidebar_frame.columnconfigure(0, weight=1)
        self.sidebar_frame.rowconfigure(0, weight=1)

        functional_sidebar = create_frame(
            parent=self.sidebar_frame,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        functional_sidebar.grid(row=0, column=0, sticky="nsew")
        functional_sidebar.columnconfigure(0, weight=1)
        functional_sidebar.rowconfigure(0, weight=0)
        functional_sidebar.rowconfigure(1, weight=1)
        functional_sidebar.rowconfigure(2, weight=0)

        self._add_normal_buttons(functional_sidebar)
        self._add_scrollable_canvas(functional_sidebar)
        self._add_delete_table_section(functional_sidebar)

    def _add_normal_buttons(self, sidebar: tk.Frame):
        """Add buttons to the sidebar."""
        normal_buttons_frame = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        normal_buttons_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=(10, 0))
        normal_buttons_frame.columnconfigure(0, weight=1)

        create_table_label = self._create_clickable_label(
            parent=normal_buttons_frame,
            text="Create New Table",
            command=self.app.table_manager.create_new_table,
            anchor="center",
        )
        create_table_label.grid(row=0, column=0, pady=10, sticky="ew")
        self.add_custom_hover(create_table_label)

        separator = tk.Frame(
            normal_buttons_frame,
            height=self.dimensions["separator_height"],
            bg=self.colors["separator"],
        )
        separator.grid(row=1, column=0, sticky="ew", pady=5)

    def _on_canvas_configure(self, event):
        """Update the table_labels_frame width to match the canvas width."""
        self.canvas.itemconfig(self.table_labels_window, width=event.width)

    def _add_scrollable_canvas(self, sidebar: tk.Frame):
        """Add scrollable canvas for table labels within a single frame."""
        scrollable_container = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        scrollable_container.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
        scrollable_container.columnconfigure(0, weight=1)
        scrollable_container.rowconfigure(0, weight=1)

        self.canvas = tk.Canvas(
            scrollable_container,
            bg=self.colors["sidebar"],
            highlightthickness=0,
        )
        self.canvas.grid(row=0, column=0, sticky="nsew")

        custom_scrollbar_design(self.style, self.colors)

        self.scrollbar = ttk.Scrollbar(
            scrollable_container,
            orient="vertical",
            command=self.canvas.yview,
            style="Custom.Vertical.TScrollbar",
        )
        self.scrollbar.grid(row=0, column=1, sticky="ns")

        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.table_labels_frame = tk.Frame(self.canvas, bg=self.colors["sidebar"])

        # Capture the window item ID
        self.table_labels_window = self.canvas.create_window(
            (0, 0),
            window=self.table_labels_frame,
            anchor="nw",
            width=self.dimensions["sidebar_width"],
        )

        self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
        self.table_labels_frame.bind("<MouseWheel>", self._on_mouse_wheel)

        self.table_labels_frame.bind(
            "<Configure>",
            lambda event: (
                self.canvas.configure(scrollregion=self.canvas.bbox("all")),
                self._update_scrollbar(
                    scrollable_container, self.canvas, self.scrollbar
                ),
            ),
        )
        scrollable_container.bind(
            "<Configure>",
            lambda event: self._update_scrollbar(
                scrollable_container, self.canvas, self.scrollbar
            ),
        )

        # Bind the canvas resize to update the table_labels_frame width
        self.canvas.bind("<Configure>", self._on_canvas_configure)

    def _on_mouse_wheel(self, event):
        """Handle mouse wheel scrolling only if scrollbar is visible."""
        if self.scrollbar.winfo_viewable():
            self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def _update_scrollbar(self, scrollbar_frame, canvas, scrollbar):
        """Update scrollbar visibility based on content size."""
        canvas.update_idletasks()
        canvas_height = scrollbar_frame.winfo_height()
        content_height = self.table_labels_frame.winfo_reqheight()

        if content_height > canvas_height:
            scrollbar.grid()
            canvas.configure(yscrollcommand=scrollbar.set)
            canvas.bind(
                "<MouseWheel>",
                lambda event: canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"),
            )
        else:
            scrollbar.grid_remove()
            canvas.configure(yscrollcommand=lambda *args: None)
            canvas.unbind("<MouseWheel>")

    def _add_delete_table_section(self, sidebar: tk.Frame):
        """Add delete table option to the sidebar."""
        delete_table_frame = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        delete_table_frame.grid(
            row=2, column=0, sticky="ew", padx=10, pady=(0, 10)
        )
        delete_table_frame.columnconfigure(0, weight=1)
        delete_table_frame.rowconfigure(1, weight=1)

        separator = tk.Frame(
            delete_table_frame,
            height=self.dimensions["separator_height"],
            bg=self.colors["separator"],
        )
        separator.grid(row=0, column=0, sticky="ew", pady=5)

        delete_table_label = self._create_clickable_label(
            parent=delete_table_frame,
            text="🗑 Delete Selected Table",
            command=self.app.table_manager.delete_table,
            anchor="center",
        )
        delete_table_label.grid(row=1, column=0, pady=10, sticky="ew")
        self.add_custom_hover(delete_table_label)

    def _create_clickable_label(
        self,
        parent: tk.Widget,
        text: str,
        command,
        allow_rename: bool = False,
        anchor: str = "w",
    ) -> tk.Label:
        """Create a clickable label with optional rename functionality."""
        cursor = "arrow" if allow_rename else "hand2"
        label = tk.Label(
            parent,
            text=text,
            bg=self.colors["button"],
            fg=self.colors["text"],
            cursor=cursor,
            anchor=anchor,
            font=self.fonts["text"],
        )
        label.bind("<Button-1>", lambda _: command())

        if allow_rename:
            label.bind("<Double-Button-1>", lambda _: self.app.table_manager.begin_rename(text))

        label.bind("<MouseWheel>", self._on_mouse_wheel)

        return label

    def add_custom_hover(self, widget: tk.Widget):
        """Add custom hover effects to a widget."""
        widget.bind(
            "<Enter>",
            lambda e: widget.config(bg=self.colors["button_selected"]),
        )
        widget.bind(
            "<Leave>", lambda e: widget.config(bg=self.colors["button"])
        )

    def create_table_label(self, table_name: str):
        """Create label for table."""
        label = self._create_clickable_label(
            self.table_labels_frame,
            table_name,
            lambda: self.app.load_selected_table(table_name),
            allow_rename=True,
        )
        label.pack(fill="x", padx=0, pady=5, expand=True)
        self.table_labels[table_name] = label
        self.add_custom_hover(label)
        self.sort_table_labels()

    def sort_table_labels(self):
        """Sort table labels with numeric names first, then alphabetic, then alphanumeric."""

        def sort_key(name):
            # Category 1: Starts with digits (e.g., "1. Movies")
            m = re.match(r"^(\d+)", name)
            if m:
                return (1, int(m.group(1)))

            # Category 3: Starts with letters followed by digits (e.g., "T1", "T2")
            m = re.match(r"^([A-Za-z]+)(\d+)", name)
            if m:
                return (3, m.group(1).lower(), int(m.group(2)))

            # Category 2: Starts with letters only (e.g., "a", "b", "c")
            m = re.match(r"^([A-Za-z]+)", name)
            if m:
                return (2, m.group(1).lower())

            # Category 4: Any other names
            return (4, name.lower())

        # Sort the table names using the defined sort key
        sorted_tables = sorted(
            self.app.data_manager.tables_data.keys(), key=sort_key
        )

        # Re-pack the labels in the sorted order
        for table_name in sorted_tables:
            label = self.table_labels.get(table_name)
            if label:
                label.pack_forget()
                label.pack(fill="x", padx=0, pady=5, expand=True)

    def cancel_rename(self):
        """Cancel rename operation."""
        if self.rename_entry:
            self.rename_entry.destroy()
            self.rename_entry = None


class Header:
    """Manages the header section, including labels and menus."""

    def __init__(self, root: tk.Tk, app: TableApp):
        self.root = root
        self.app = app
        self.colors = app.colors
        self.fonts = app.fonts
        self.dimensions = app.dimensions
        self.style = app.style
        self.table_name_label: Optional[tk.Label] = None
        self.lower_header_frame: Optional[tk.Frame] = None
        
        self._setup_header()

    def _setup_header(self) -> None:
        """Main setup method for the header."""
        header_frame = self._setup_main_frame()
        self._setup_upper_section(header_frame)
        self._setup_lower_section(header_frame)

    def _setup_main_frame(self) -> tk.Frame:
        """Setup and configure the main header frame."""
        header_frame = create_frame(parent=self.root, width=None, bg=self.colors["background"])
        header_frame.grid(row=0, column=1, columnspan=2, sticky="ew")
        header_frame.config(height=self.dimensions["header_height"])
        header_frame.grid_propagate(False)

        for i in range(2):
            header_frame.grid_rowconfigure(i, weight=0)
        for i in range(5):
            header_frame.grid_columnconfigure(i, weight=1 if i == 4 else 0)

        return header_frame

    def _setup_upper_section(self, parent: tk.Frame) -> None:
        """Setup the upper section of the header."""
        upper_frame = create_frame(parent=parent, width=None, bg=self.colors["background"])
        upper_frame.grid(row=0, column=0, columnspan=5, sticky="ew", pady=(0, 10))
        upper_frame.grid_columnconfigure(5, weight=1)

        self._add_upper_content(upper_frame)

    def _add_upper_content(self, frame: tk.Frame) -> None:
        """Add content to the upper section."""
        tk.Label(
            frame,
            text="Data > ",
            bg=self.colors["background"],
            fg=self.colors["header_info"],
            font=self.fonts["header_info"]
        ).grid(row=0, column=0, padx=22, pady=(22, 0), sticky="nw")

        self.table_name_label = tk.Label(
            frame,
            text=self.app.current_table_name or "No Table Selected",
            bg=self.colors["background"],
            fg=self.colors["text"],
            font=self.fonts["header_info"]
        )
        self.table_name_label.grid(row=0, column=0, padx=(88, 10), pady=(22, 0), sticky="nw")

        self._setup_settings_section(frame)

    def _setup_settings_section(self, frame: tk.Frame) -> None:
        """Setup the settings section with label and menu."""
        settings_label = tk.Label(
            frame,
            text="...",
            bg=self.colors["background"],
            fg=self.colors["text"],
            cursor="hand2",
            anchor="e",
            font=self.fonts["text"]
        )
        settings_label.grid(row=0, column=5, padx=40, pady=20, sticky="e")

        settings_menu = self._create_settings_menu()
        
        settings_label.bind("<Button-1>", lambda e: settings_menu.post(e.x_root, e.y_root))
        settings_label.bind("<Enter>", 
                          lambda _: settings_label.config(bg=self.colors["button_selected"]))
        settings_label.bind("<Leave>", 
                          lambda _: settings_label.config(bg=self.colors["background"]))

    def _create_settings_menu(self) -> tk.Menu:
        """Create and return the settings menu."""
        menu = tk.Menu(self.root, tearoff=0)
        menu_items = [
            ("Export Table", self.app.table_manager.export_table),
            ("Import Table", self.app.table_manager.import_file),
            ("Rename Headers", self.app.table_manager.rename_headers)
        ]
        for label, command in menu_items:
            menu.add_command(label=label, command=command)
        return menu

    def _setup_lower_section(self, parent: tk.Frame) -> None:
        """Setup the lower section of the header."""
        self.lower_header_frame = create_frame(
            parent=parent, 
            width=None, 
            bg=self.colors["background"]
        )
        self.lower_header_frame.grid(row=1, column=0, columnspan=5, sticky="ew")


class FilterControls:
    """Manages filtering logic and UI components."""

    FILTER_OPTIONS = {
        "is": lambda cell, text: cell == text,
        "is not": lambda cell, text: cell != text,
        "contains": lambda cell, text: text in cell,
        "does not contain": lambda cell, text: text not in cell,
        "starts with": lambda cell, text: cell.startswith(text),
        "ends with": lambda cell, text: cell.endswith(text),
        "is empty": lambda cell, _: cell == "",
        "is not empty": lambda cell, _: cell != "",
    }

    def __init__(self, parent: tk.Frame, app: TableApp):
        self._initialize_attributes(parent, app)
        self._setup_variables()
        self.create_filter_controls()

    def _initialize_attributes(self, parent: tk.Frame, app: TableApp):
        """Initialize basic attributes."""
        self.app = app
        self.root = parent
        self.colors = app.colors
        self.fonts = app.fonts
        self.style = app.style

    def _setup_variables(self):
        """Setup tkinter variables."""
        self.filter_header_var = tk.StringVar(value="All")
        self.filter_option_var = tk.StringVar(value="contains")
        self.filter_text_var = tk.StringVar()

    def create_filter_controls(self):
        """Create and configure filter controls."""
        filter_components = self._create_filter_components()
        self._configure_filter_components(*filter_components)
        self._bind_filter_events()

    def _create_filter_components(self):
        """Create filter UI components."""
        headers = ["All"] + self.app.data_manager.headers.get(
            self.app.current_table_name, []
        )
        filter_frame, header_dropdown, option_dropdown, text_entry = custom_filter_design(
            self.root,
            self.style,
            headers=headers,
            filter_types=list(self.FILTER_OPTIONS.keys()),
            filter_font=self.fonts["filter"],
            filter_combobox_font=self.fonts["filter_combobox"],
            colors=self.colors,
        )
        filter_frame.grid(row=0, column=1, columnspan=4, padx=100, pady=0, sticky="ew")
        return header_dropdown, option_dropdown, text_entry

    def _configure_filter_components(self, header_dropdown, option_dropdown, text_entry):
        """Configure filter components with variables."""
        self.filter_header_dropdown = header_dropdown
        self.filter_option_dropdown = option_dropdown
        self.filter_text_entry = text_entry

        self.filter_header_dropdown["textvariable"] = self.filter_header_var
        self.filter_option_dropdown["textvariable"] = self.filter_option_var
        self.filter_text_entry["textvariable"] = self.filter_text_var

    def _bind_filter_events(self):
        """Bind events to filter components."""
        self.filter_header_dropdown.bind("<<ComboboxSelected>>", self.apply_filter)
        self.filter_option_dropdown.bind(
            "<<ComboboxSelected>>",
            lambda event: [self.update_filter_text_state(event), self.apply_filter()],
        )
        self.filter_text_entry.bind("<KeyRelease>", self.apply_filter)
        self.filter_text_entry.bind("<Return>", self.apply_filter)

    def update_filter_text_state(self, event=None):
        """Enable or disable the filter text entry based on filter option."""
        option = self.filter_option_var.get()
        is_special_option = option in ["is empty", "is not empty"]
        
        self.filter_text_entry.config(state="disabled" if is_special_option else "normal")
        if is_special_option:
            self.filter_text_var.set("")
            self.apply_filter()

    def apply_filter(self, event=None):
        """Apply filter to table data based on selected criteria."""
        if not self._is_filtering_possible():
            return

        filtered_data, displayed_indices = self._filter_data()
        self._update_display(filtered_data, displayed_indices)

    def _is_filtering_possible(self):
        """Check if filtering is possible."""
        return bool(self.app.current_table_name and self.app.current_sheet)

    def _filter_data(self):
        """Filter data based on current filter settings."""
        header = self.filter_header_var.get()
        option = self.filter_option_var.get()
        text = self.filter_text_var.get().lower()
        original_data = self.app.data_manager.tables_data[self.app.current_table_name]["data"]

        filtered_data = []
        displayed_indices = []

        target_indices = self._get_target_indices(header)
        filter_func = self.FILTER_OPTIONS[option]

        for i, row in enumerate(original_data):
            if self._row_matches(row, target_indices, filter_func, text):
                filtered_data.append(row)
                displayed_indices.append(i)

        return filtered_data, displayed_indices

    def _get_target_indices(self, header):
        """Get indices to filter on based on selected header."""
        if header == "All":
            return range(len(self.app.data_manager.headers[self.app.current_table_name]))
        try:
            return [self.app.data_manager.headers[self.app.current_table_name].index(header)]
        except ValueError:
            return []

    def _row_matches(self, row, target_indices, filter_func, text):
        """Check if row matches filter criteria."""
        return any(
            filter_func(str(row[idx]).lower(), text)
            for idx in target_indices
        )

    def _update_display(self, filtered_data, displayed_indices):
        """Update the display with filtered data."""
        try:
            self.app.displayed_row_indices = displayed_indices
            self.app.current_sheet.set_sheet_data(filtered_data)
        except tk.TclError as e:
            print(f"Error applying filter: {e}")


if __name__ == "__main__":
    set_dpi_awareness()
    root = tk.Tk()
    app = TableApp(root)
    root.mainloop()
ASSISTANT
Here is the updated Python code, with the `TableManager` class split into three separate classes: `TableOperationsManager`, `TableDisplayManager`, and `TableIOManager`. This should improve maintainability and readability while retaining the original functionality.

```python
import ctypes
import csv
import json
import re
import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox, simpledialog, ttk
from typing import Any, Optional

from tksheet import Sheet


def set_dpi_awareness():
    """Enable DPI awareness for high DPI settings."""
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    except Exception as e:
        print(f"Error setting DPI awareness: {e}")


def create_frame(parent: tk.Widget, width: Optional[int] = None, bg: str = "SystemButtonFace") -> tk.Frame:
    """Creates a frame with specified width and background color."""
    frame = tk.Frame(parent, width=width, bg=bg, bd=0, relief="flat")
    if width:
        frame.config(width=width)
    return frame


def custom_filter_design(
    master,
    style: ttk.Style,
    headers=None,
    filter_types=None,
    filter_font=None,
    filter_combobox_font=None,
    colors=None,
):
    """Creates a custom filter frame with all components."""
    filter_frame = ttk.Frame(master, style="Custom.TFrame")

    # Configure styles
    style.configure(
        "Custom.TFrame",
        background=colors["background"],
        relief="flat",
        borderwidth=0,
    )
    style.configure(
        "TCombobox",
        relief="flat",
        borderwidth=0,
        background=colors["background"],
        fieldbackground=colors["background"],
    )
    style.map(
        "TCombobox",
        fieldbackground=[("readonly", colors["background"])],
        background=[("readonly", colors["background"])],
    )
    style.configure(
        "TEntry",
        relief="flat",
        borderwidth=0,
        background=colors["background"],
    )
    style.configure("Line.TFrame", background=colors["filter_line"])

    # Create widgets
    header_combobox = ttk.Combobox(
        filter_frame,
        values=headers,
        width=15,
        font=filter_combobox_font,
        state="readonly",
    )
    filtertype_combobox = ttk.Combobox(
        filter_frame,
        values=filter_types,
        width=15,
        font=filter_combobox_font,
        state="readonly",
    )
    filter_entry = ttk.Entry(filter_frame, font=filter_font)
    underline = ttk.Frame(filter_frame, height=1, style="Line.TFrame")

    # Layout widgets
    header_combobox.grid(row=0, column=0, padx=(0, 30), pady=2, sticky="ew")
    filtertype_combobox.grid(row=0, column=1, padx=2, pady=2, sticky="ew")
    filter_entry.grid(
        row=1, column=0, columnspan=2, padx=2, pady=(2, 0), sticky="ew"
    )
    underline.grid(row=2, column=0, columnspan=2, sticky="ew", pady=(0, 2))

    # Prevent text selection in comboboxes
    for combobox in (header_combobox, filtertype_combobox):
        combobox.bind("<FocusIn>", lambda event: event.widget.selection_clear())

    # Configure column weights
    filter_frame.columnconfigure((0, 1), weight=1)

    # Ensure the underline doesn't resize vertically
    underline.pack_propagate(False)

    return (
        filter_frame,
        header_combobox,
        filtertype_combobox,
        filter_entry,
    )


def custom_scrollbar_design(style: ttk.Style, colors=None):
    """Configure custom scrollbar style."""
    style.configure(
        "Custom.Vertical.TScrollbar",
        troughcolor=colors["scrollbar_trough"],
        background=colors["scrollbar_background"],
        borderwidth=0,
        arrowcolor=colors["scrollbar_arrow"],
    )
    style.map(
        "Custom.Vertical.TScrollbar",
        background=[("active", colors["scrollbar_active"])],
    )
    style.layout(
        "Custom.Vertical.TScrollbar",
        [
            (
                "Vertical.Scrollbar.trough",
                {
                    "children": [
                        (
                            "Vertical.Scrollbar.thumb",
                            {"expand": "1", "sticky": "ns"},
                        )
                    ],
                    "sticky": "ns",
                },
            )
        ],
    )


class TableApp:
    """Main application controller for database table visualization."""

    def __init__(self, root: tk.Tk):
        """Initialize the TableApp with basic configuration and UI setup."""
        self._initialize_root(root)
        self._initialize_configurations()
        self._initialize_core_components()
        self._setup_ui_components()
        self._load_initial_data()

    def _initialize_root(self, root: tk.Tk):
        """Set up the root window properties."""
        self.root = root
        self.root.title("Database")
        self.root.geometry("1920x1080")
        self.root.minsize(1435, 910)

    def _initialize_configurations(self):
        """Initialize all configurations including dimensions, fonts, colors, and style."""
        self._set_dimensions()
        self._set_fonts()
        self._set_colors()
        self._set_style()

    def _set_dimensions(self):
        """Define application dimensions."""
        self.dimensions = {
            "sidebar_width": 400,
            "spacer_frame_width": 100,
            "header_height": 190,
            "separator_height": 1
        }

    def _set_fonts(self):
        """Define application fonts."""
        self.fonts = {
            "text": ("Literata", 12),
            "tksheet": ("Literata", 12, "normal"),
            "header_info": ("Literata", 10),
            "filter": ("Literata", 12),
            "filter_combobox": ("Literata", 8)
        }

    def _set_colors(self):
        """Define application colors."""
        self.colors = {
            "text": "#333333",
            "background": "#FFFFFF",
            "sidebar": "#F7F8FC",
            "button": "#F7F8FC",
            "button_selected": "#EAEDEF",
            "separator": "#333333",
            "header_info": "#999999",
            "scrollbar_trough": "#F7F8FC",
            "scrollbar_background": "#c0c1c4",
            "scrollbar_arrow": "#333333",
            "scrollbar_active": "#878789",
            "filter_line": "#00bcf0"
        }

    def _set_style(self):
        """Initialize and configure the application style."""
        self.style = ttk.Style()
        self.style.theme_use("default")

    def _initialize_core_components(self):
        """Initialize core application components and state variables."""
        self.current_table_name: str | None = None
        self.current_sheet: Sheet | None = None
        self.displayed_row_indices: list[int] = []
        
        self.data_manager = DataManager(self)
        self.table_operations = TableOperationsManager(self)
        self.table_display = TableDisplayManager(self)
        self.table_io = TableIOManager(self)

    def _setup_ui_components(self):
        """Set up all UI components and their layout."""
        self._configure_grid()
        self._create_main_components()
        self._create_auxiliary_frames()

    def _configure_grid(self):
        """Configure the root window grid layout."""
        self.root.grid_rowconfigure(0, weight=0)
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=0)
        self.root.grid_columnconfigure(1, weight=0, 
                                     minsize=self.dimensions["spacer_frame_width"])
        self.root.grid_columnconfigure(2, weight=3)

    def _create_main_components(self):
        """Create main UI components."""
        self.sidebar = Sidebar(self.root, self)
        self.header = Header(self.root, self)
        self.filter_controls = FilterControls(self.header.lower_header_frame, self)

    def _create_auxiliary_frames(self):
        """Create auxiliary frames for layout purposes."""
        self._create_spacer_frame()
        self._create_table_frame()

    def _create_spacer_frame(self):
        """Create and configure the spacer frame."""
        spacer = create_frame(
            parent=self.root,
            width=self.dimensions["spacer_frame_width"],
            bg=self.colors["background"]
        )
        spacer.grid(row=1, column=1, sticky="nsew")
        spacer.grid_propagate(False)

    def _create_table_frame(self):
        """Create and configure the main table frame."""
        self.table_frame = create_frame(
            parent=self.root,
            width=None,
            bg=self.colors["background"]
        )
        self.table_frame.grid(row=1, column=2, sticky="nsew")
        self.table_frame.grid_rowconfigure(0, weight=1)
        self.table_frame.grid_columnconfigure(0, weight=1)

    def _load_initial_data(self):
        """Load initial application data."""
        self.data_manager.load_tables()

    # Public methods
    def load_selected_table(self, table_name: str):
        """Load and display the selected table."""
        self.table_display.load_selected_table(table_name)

    def refresh_table(self):
        """Refresh the currently displayed table."""
        if self.current_table_name:
            self.load_selected_table(self.current_table_name)

    def apply_filter(self):
        """Apply the current filter to the table."""
        self.filter_controls.apply_filter()


class DataManager:
    """Handles data persistence, loading, and saving."""

    def __init__(self, app: TableApp):
        self.app = app
        self.save_file_path = Path(__file__).parent / "Data.json"
        self.tables_data: dict[str, dict] = {}
        self.headers: dict[str, list[str]] = {}

    def load_tables(self):
        """Load tables from file."""
        if not self.save_file_path.exists():
            return
        try:
            with self.save_file_path.open("r", encoding="utf-8") as file:
                all_data = json.load(file)
        except Exception as e:
            messagebox.showerror("Load Error", f"Failed to load tables: {e}")
            return
        for table_name, data in all_data.items():
            if not isinstance(data, list) or not data:
                continue
            headers, table_data = data[0], data[1:]
            self.headers[table_name] = headers
            self.tables_data[table_name] = {"headers": headers, "data": table_data}
            # Inform Sidebar to create table label
            self.app.sidebar.create_table_label(table_name)
        self.app.sidebar.sort_table_labels()

    def save_data(self):
        """Save all tables data."""
        all_data = {}
        for table_name, table_info in self.tables_data.items():
            all_data[table_name] = [table_info["headers"]] + table_info["data"]
        try:
            with self.save_file_path.open("w", encoding="utf-8") as file:
                json.dump(all_data, file, indent=4)
        except Exception as e:
            print(f"Error saving data: {e}")


class TableOperationsManager:
    """Handles creating, deleting, and renaming tables."""

    def __init__(self, app: TableApp):
        self.app = app

    def create_new_table(self):
        """Create a new table."""
        existing_numbers = [
            int(name.split(" ")[1])
            for name in self.app.data_manager.tables_data
            if name.startswith("Table ") and name.split(" ")[1].isdigit()
        ]
        next_number = max(existing_numbers, default=0) + 1
        table_name = f"Table {next_number}"
        self.add_table(table_name)
        self.app.table_display.load_selected_table(table_name)

    def add_table(
        self,
        table_name: str,
        data: list[list[str]] | None = None,
        headers: Optional[list[str]] = None,
    ):
        """Add a new table."""
        if headers:
            self.app.data_manager.headers[table_name] = headers
        else:
            default_headers = [
                "Column 1",
                "Column 2",
                "Column 3",
                "Column 4",
                "Column 5",
            ]
            self.app.data_manager.headers[table_name] = default_headers
        self.app.data_manager.tables_data[table_name] = {
            "headers": self.app.data_manager.headers[table_name],
            "data": data
            or [
                ["" for _ in range(len(self.app.data_manager.headers[table_name]))]
                for _ in range(10)
            ],
        }
        self.app.sidebar.create_table_label(table_name)
        self.app.data_manager.save_data()

    def delete_table(self):
        """Delete selected table."""
        if (
            not self.app.current_table_name
            or self.app.current_table_name not in self.app.data_manager.tables_data
        ):
            messagebox.showwarning(
                "No Table Selected", "Please select a valid table to delete."
            )
            return
        if messagebox.askyesno(
            "Delete Table",
            f"Are you sure you want to delete the table '{self.app.current_table_name}'?",
        ):
            self.remove_table(self.app.current_table_name)

    def remove_table(self, table_name: str):
        """Remove a table."""
        if self.app.current_table_name == table_name and self.app.current_sheet:
            self.app.current_sheet.destroy()
            self.app.current_sheet = None
        label = self.app.sidebar.table_labels.get(table_name)
        if label:
            label.destroy()
        if table_name in self.app.data_manager.tables_data:
            del self.app.data_manager.tables_data[table_name]
        if table_name in self.app.data_manager.headers:
            del self.app.data_manager.headers[table_name]
        if table_name in self.app.sidebar.table_labels:
            del self.app.sidebar.table_labels[table_name]
        self.app.current_table_name = None
        self.app.sidebar.selected_table_label = None
        self.app.data_manager.save_data()
        self.app.sidebar.sort_table_labels()

    def rename_headers(self):
        """Rename table headers."""
        if not self.app.current_table_name:
            messagebox.showwarning(
                "No Table Selected", "Please select a table to rename headers."
            )
            return
        current_headers = self.app.data_manager.headers[self.app.current_table_name]
        new_headers = simpledialog.askstring(
            "Rename Headers",
            "Enter new headers (comma-separated):",
            initialvalue=", ".join(current_headers),
        )
        if new_headers:
            header_list = [header.strip() for header in new_headers.split(",")]
            if not header_list:
                messagebox.showerror("Invalid Headers", "Header list cannot be empty.")
                return
            self.app.data_manager.headers[self.app.current_table_name] = header_list
            self.app.data_manager.tables_data[self.app.current_table_name][
                "headers"
            ] = header_list
            if self.app.current_sheet:
                try:
                    self.app.current_sheet.headers(header_list)
                except tk.TclError as e:
                    messagebox.showerror("Error", f"Failed to rename headers: {e}")

            self.app.filter_controls.filter_header_var.set("All")
            self.app.filter_controls.filter_header_dropdown["values"] = [
                "All"
            ] + header_list
            self.app.apply_filter()

            self.app.data_manager.save_data()

    def begin_rename(self, table_name: str):
        """Start renaming a table."""
        if table_name not in self.app.sidebar.table_labels:
            messagebox.showerror("Error", f"Table '{table_name}' not found.")
            return
        label = self.app.sidebar.table_labels[table_name]
        self.cancel_rename()
        self.app.sidebar.rename_entry = tk.Entry(
            self.app.sidebar.table_labels_frame,
            bg=label.cget("bg"),
            fg=self.app.colors["text"],
            relief="flat",
        )
        self.app.sidebar.rename_entry.insert(0, table_name)
        self.app.sidebar.rename_entry.place(
            x=label.winfo_x(),
            y=label.winfo_y(),
            width=label.winfo_width(),
            height=label.winfo_height(),
        )
        self.app.sidebar.rename_entry.focus()
        self.app.sidebar.rename_entry.select_range(0, tk.END)
        self.app.sidebar.rename_entry.bind(
            "<Return>", lambda event: self.end_rename(table_name)
        )
        self.app.sidebar.rename_entry.bind("<FocusOut>", lambda event: self.cancel_rename())

    def end_rename(self, old_name: str):
        """Finalize table renaming."""
        new_name = self.app.sidebar.rename_entry.get().strip()
        if not new_name:
            messagebox.showerror("Invalid Name", "Table name cannot be empty.")
            self.app.sidebar.rename_entry.focus_set()
            return
        if new_name in self.app.data_manager.tables_data and new_name != old_name:
            messagebox.showerror(
                "Duplicate Name", f"A table named '{new_name}' already exists."
            )
            self.app.sidebar.rename_entry.focus_set()
            return
        if new_name != old_name:
            self.update_table_name(old_name, new_name)
            self.app.table_display.load_selected_table(new_name)
        self.cancel_rename()

    def update_table_name(self, old_name: str, new_name: str):
        """Update table name and resources."""
        self.app.data_manager.tables_data[new_name] = self.app.data_manager.tables_data.pop(
            old_name
        )
        self.app.data_manager.headers[new_name] = self.app.data_manager.headers.pop(
            old_name
        )
        label = self.app.sidebar.table_labels.pop(old_name)
        label.config(text=new_name)
        label.bind(
            "<Button-1>", lambda event: self.app.table_display.load_selected_table(new_name)
        )
        label.bind(
            "<Double-1>", lambda event: self.begin_rename(new_name)
        )
        self.app.sidebar.table_labels[new_name] = label
        if self.app.sidebar.selected_table_label == label:
            try:
                label.config(bg=self.app.colors["button_selected"])
            except tk.TclError:
                pass
        self.app.data_manager.save_data()
        self.app.sidebar.sort_table_labels()

    def cancel_rename(self):
        """Cancel rename operation."""
        if self.app.sidebar.rename_entry:
            self.app.sidebar.rename_entry.destroy()
            self.app.sidebar.rename_entry = None


class TableDisplayManager:
    """Handles loading and displaying tables and related events."""

    def __init__(self, app: TableApp):
        self.app = app

    def load_selected_table(self, table_name: str):
        """Display selected table."""
        if self.app.current_sheet:
            self.app.current_sheet.pack_forget()
            self.app.current_sheet.destroy()
            self.app.current_sheet = None
        if self.app.sidebar.selected_table_label:
            try:
                self.app.sidebar.selected_table_label.config(
                    bg=self.app.colors["button"]
                )
            except tk.TclError:
                self.app.sidebar.selected_table_label = None

        if table_name not in self.app.data_manager.tables_data:
            messagebox.showerror("Error", f"Table '{table_name}' does not exist.")
            self.app.current_table_name = None
            self.app.sidebar.selected_table_label = None
            return

        table_info = self.app.data_manager.tables_data[table_name]
        headers = table_info["headers"]
        data = table_info["data"]
        try:
            sheet = Sheet(
                self.app.table_frame,
                data=data,
                show_table=True,
                headers=headers,
                font=self.app.fonts["tksheet"],
                header_font=self.app.fonts["tksheet"],
                auto_resize_columns=True,
            )
            sheet.set_options(
                table_fg=self.app.colors["text"], header_fg=self.app.colors["text"]
            )
            sheet.enable_bindings()
            sheet.extra_bindings(
                [
                    ("end_edit_cell", self.on_cell_edit),
                    ("end_delete_columns", self.on_columns_deleted),
                ]
            )
            sheet.pack(expand=True, fill="both")
            self.app.current_sheet = sheet
            self.app.current_table_name = table_name

            if self.app.header.table_name_label:
                self.app.header.table_name_label.config(text=self.app.current_table_name)
            else:
                self.app.header.table_name_label = tk.Label(
                    self.app.root,
                    text=self.app.current_table_name,
                    bg=self.app.colors["background"],
                    fg=self.app.colors["text"],
                    font=self.app.fonts["header_info"],
                )
                self.app.header.table_name_label.grid(
                    row=0, column=0, padx=(60, 10), pady=(5, 0), sticky="nw"
                )

            label = self.app.sidebar.table_labels.get(table_name)
            if label:
                self.app.sidebar.selected_table_label = label
                try:
                    self.app.sidebar.selected_table_label.config(
                        bg=self.app.colors["button_selected"]
                    )
                except tk.TclError:
                    self.app.sidebar.selected_table_label = None
                    messagebox.showerror(
                        "Error", f"Failed to update the label for '{table_name}'."
                    )
            else:
                self.app.sidebar.selected_table_label = None
                messagebox.showerror("Error", f"Label for '{table_name}' not found.")

            self.app.filter_controls.filter_header_var.set("All")
            self.app.filter_controls.filter_header_dropdown["values"] = ["All"] + headers

            self.app.filter_controls.filter_option_var.set("contains")
            self.app.filter_controls.update_filter_text_state()

            self.app.apply_filter()
        except Exception as e:
            messagebox.showerror(
                "Sheet Error", f"Failed to load table '{table_name}': {e}"
            )
            self.app.current_table_name = None
            self.app.sidebar.selected_table_label = None

    def on_cell_edit(self, event=None):
        """Handle cell edits."""
        if self.app.current_table_name and self.app.current_sheet:
            sheet_data = self.app.current_sheet.get_sheet_data()
            for idx, row in enumerate(sheet_data):
                if idx < len(self.app.displayed_row_indices):
                    data_idx = self.app.displayed_row_indices[idx]
                    self.app.data_manager.tables_data[self.app.current_table_name][
                        "data"
                    ][data_idx] = row
                else:
                    # Handle new rows by appending to the underlying data
                    self.app.data_manager.tables_data[self.app.current_table_name][
                        "data"
                    ].append(row)
            self.app.data_manager.save_data()

    def on_columns_deleted(self, event):
        """Handle column deletion and update filter headers."""
        if not self.app.current_table_name or not self.app.current_sheet:
            return
        new_headers = self.app.current_sheet.headers()
        self.app.data_manager.headers[self.app.current_table_name] = new_headers
        self.app.filter_controls.filter_header_dropdown["values"] = ["All"] + new_headers
        self.app.filter_controls.filter_header_var.set("All")
        self.app.filter_controls.filter_option_var.set("contains")
        self.app.filter_controls.filter_text_var.set("")
        self.app.filter_controls.filter_text_entry.config(state="normal")
        self.app.apply_filter()


class TableIOManager:
    """Handles importing and exporting tables."""

    def __init__(self, app: TableApp):
        self.app = app

    def import_file(self):
        """Import table from file."""
        file_path = filedialog.askopenfilename(
            title="Import File",
            filetypes=[
                ("All Supported Files", "*.json *.csv"),
                ("JSON files", "*.json"),
                ("CSV files", "*.csv"),
            ],
        )
        if not file_path:
            return
        try:
            if file_path.endswith(".csv"):
                with open(file_path, newline="", encoding="utf-8") as csvfile:
                    data = list(csv.reader(csvfile))
            elif file_path.endswith(".json"):
                with open(file_path, "r", encoding="utf-8") as jsonfile:
                    data = json.load(jsonfile)
            else:
                raise ValueError("Unsupported file format.")
            if (
                not data
                or not isinstance(data, list)
                or not all(isinstance(row, list) for row in data)
            ):
                raise ValueError("Invalid data format in the file.")
            headers, table_data = data[0], data[1:]
            self.add_table_from_data(file_path, headers, table_data)
        except Exception as e:
            messagebox.showerror("File Import Error", str(e))

    def add_table_from_data(
        self, file_path: str, headers: list[str], table_data: list[list[str]]
    ):
        """Add a table from file data."""
        table_name = Path(file_path).stem
        table_name = self.ensure_unique_table_name(table_name)
        self.app.table_operations.add_table(table_name, data=table_data, headers=headers)
        self.app.table_display.load_selected_table(table_name)
        self.app.data_manager.save_data()

    def ensure_unique_table_name(self, table_name: str) -> str:
        """Ensure table name is unique."""
        original_name = table_name
        counter = 1
        while table_name in self.app.data_manager.tables_data:
            table_name = f"{original_name} (New {counter})"
            counter += 1
        return table_name

    def export_table(self):
        """Export current table to file."""
        if (
            not self.app.current_table_name
            or self.app.current_table_name not in self.app.data_manager.tables_data
        ):
            messagebox.showwarning(
                "No Table Selected", "Please select a table to export."
            )
            return
        file_path = filedialog.asksaveasfilename(
            title="Export File",
            defaultextension=".json",
            filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")],
            initialfile=self.app.current_table_name,
        )
        if not file_path:
            return
        try:
            data = [
                self.app.data_manager.headers[self.app.current_table_name]
            ] + self.app.data_manager.tables_data[self.app.current_table_name]["data"]
            if file_path.endswith(".csv"):
                self.save_table_data(file_path, data, "csv")
            elif file_path.endswith(".json"):
                with open(file_path, "w", encoding="utf-8") as file:
                    json.dump(data, file, indent=4)
            else:
                raise ValueError("Unsupported file format.")
            self.app.data_manager.save_data()
            messagebox.showinfo(
                "Export Successful",
                f"Table '{self.app.current_table_name}' has been exported successfully.",
            )
        except Exception as e:
            messagebox.showerror(
                "Export Failed", f"An error occurred during export: {e}"
            )

    def save_table_data(self, file_path: str, data: list[list[str]], format: str):
        """Save table data in specified format."""
        match format:
            case "csv":
                with open(file_path, "w", newline="", encoding="utf-8") as file:
                    csv.writer(file).writerows(data)
            case "json":
                with open(file_path, "w", encoding="utf-8") as file:
                    json.dump(data, file, indent=4)
            case _:
                raise ValueError("Unsupported file format.")


class Sidebar:
    """Handles all sidebar-related UI and interactions."""

    def __init__(self, root: tk.Tk, app: TableApp):
        self.root = root
        self.app = app
        self.colors = app.colors
        self.fonts = app.fonts
        self.dimensions = app.dimensions
        self.style = app.style

        # Initialize variables
        self.table_labels_frame: Optional[tk.Frame] = None
        self.table_labels: dict[str, tk.Label] = {}
        self.selected_table_label: Optional[tk.Label] = None
        self.rename_entry: Optional[tk.Entry] = None

        self.create_sidebar()

    def create_sidebar(self):
        """Create the sidebar UI components."""
        self.sidebar_frame = create_frame(
            parent=self.root,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        self.sidebar_frame.grid(row=0, column=0, rowspan=2, sticky="ns")
        self.sidebar_frame.grid_propagate(False)
        self.sidebar_frame.columnconfigure(0, weight=1)
        self.sidebar_frame.rowconfigure(0, weight=1)

        functional_sidebar = create_frame(
            parent=self.sidebar_frame,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        functional_sidebar.grid(row=0, column=0, sticky="nsew")
        functional_sidebar.columnconfigure(0, weight=1)
        functional_sidebar.rowconfigure(0, weight=0)
        functional_sidebar.rowconfigure(1, weight=1)
        functional_sidebar.rowconfigure(2, weight=0)

        self._add_normal_buttons(functional_sidebar)
        self._add_scrollable_canvas(functional_sidebar)
        self._add_delete_table_section(functional_sidebar)

    def _add_normal_buttons(self, sidebar: tk.Frame):
        """Add buttons to the sidebar."""
        normal_buttons_frame = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        normal_buttons_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=(10, 0))
        normal_buttons_frame.columnconfigure(0, weight=1)

        create_table_label = self._create_clickable_label(
            parent=normal_buttons_frame,
            text="Create New Table",
            command=self.app.table_operations.create_new_table,
            anchor="center",
        )
        create_table_label.grid(row=0, column=0, pady=10, sticky="ew")
        self.add_custom_hover(create_table_label)

        separator = tk.Frame(
            normal_buttons_frame,
            height=self.dimensions["separator_height"],
            bg=self.colors["separator"],
        )
        separator.grid(row=1, column=0, sticky="ew", pady=5)

    def _on_canvas_configure(self, event):
        """Update the table_labels_frame width to match the canvas width."""
        self.canvas.itemconfig(self.table_labels_window, width=event.width)

    def _add_scrollable_canvas(self, sidebar: tk.Frame):
        """Add scrollable canvas for table labels within a single frame."""
        scrollable_container = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        scrollable_container.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
        scrollable_container.columnconfigure(0, weight=1)
        scrollable_container.rowconfigure(0, weight=1)

        self.canvas = tk.Canvas(
            scrollable_container,
            bg=self.colors["sidebar"],
            highlightthickness=0,
        )
        self.canvas.grid(row=0, column=0, sticky="nsew")

        custom_scrollbar_design(self.style, self.colors)

        self.scrollbar = ttk.Scrollbar(
            scrollable_container,
            orient="vertical",
            command=self.canvas.yview,
            style="Custom.Vertical.TScrollbar",
        )
        self.scrollbar.grid(row=0, column=1, sticky="ns")

        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.table_labels_frame = tk.Frame(self.canvas, bg=self.colors["sidebar"])

        # Capture the window item ID
        self.table_labels_window = self.canvas.create_window(
            (0, 0),
            window=self.table_labels_frame,
            anchor="nw",
            width=self.dimensions["sidebar_width"],
        )

        self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
        self.table_labels_frame.bind("<MouseWheel>", self._on_mouse_wheel)

        self.table_labels_frame.bind(
            "<Configure>",
            lambda event: (
                self.canvas.configure(scrollregion=self.canvas.bbox("all")),
                self._update_scrollbar(
                    scrollable_container, self.canvas, self.scrollbar
                ),
            ),
        )
        scrollable_container.bind(
            "<Configure>",
            lambda event: self._update_scrollbar(
                scrollable_container, self.canvas, self.scrollbar
            ),
        )

        # Bind the canvas resize to update the table_labels_frame width
        self.canvas.bind("<Configure>", self._on_canvas_configure)

    def _on_mouse_wheel(self, event):
        """Handle mouse wheel scrolling only if scrollbar is visible."""
        if self.scrollbar.winfo_viewable():
            self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def _update_scrollbar(self, scrollbar_frame, canvas, scrollbar):
        """Update scrollbar visibility based on content size."""
        canvas.update_idletasks()
        canvas_height = scrollbar_frame.winfo_height()
        content_height = self.table_labels_frame.winfo_reqheight()

        if content_height > canvas_height:
            scrollbar.grid()
            canvas.configure(yscrollcommand=scrollbar.set)
            canvas.bind(
                "<MouseWheel>",
                lambda event: canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"),
            )
        else:
            scrollbar.grid_remove()
            canvas.configure(yscrollcommand=lambda *args: None)
            canvas.unbind("<MouseWheel>")

    def _add_delete_table_section(self, sidebar: tk.Frame):
        """Add delete table option to the sidebar."""
        delete_table_frame = create_frame(
            parent=sidebar,
            width=self.dimensions["sidebar_width"],
            bg=self.colors["sidebar"],
        )
        delete_table_frame.grid(
            row=2, column=0, sticky="ew", padx=10, pady=(0, 10)
        )
        delete_table_frame.columnconfigure(0, weight=1)
        delete_table_frame.rowconfigure(1, weight=1)

        separator = tk.Frame(
            delete_table_frame,
            height=self.dimensions["separator_height"],
            bg=self.colors["separator"],
        )
        separator.grid(row=0, column=0, sticky="ew", pady=5)

        delete_table_label = self._create_clickable_label(
            parent=delete_table_frame,
            text="🗑 Delete Selected Table",
            command=self.app.table_operations.delete_table,
            anchor="center",
        )
        delete_table_label.grid(row=1, column=0, pady=10, sticky="ew")
        self.add_custom_hover(delete_table_label)

    def _create_clickable_label(
        self,
        parent: tk.Widget,
        text: str,
        command,
        allow_rename: bool = False,
        anchor: str = "w",
    ) -> tk.Label:
        """Create a clickable label with optional rename functionality."""
        cursor = "arrow" if allow_rename else "hand2"
        label = tk.Label(
            parent,
            text=text,
            bg=self.colors["button"],
            fg=self.colors["text"],
            cursor=cursor,
            anchor=anchor,
            font=self.fonts["text"],
        )
        label.bind("<Button-1>", lambda _: command())

        if allow_rename:
            label.bind("<Double-1>", lambda _: self.app.table_operations.begin_rename(text))

        label.bind("<MouseWheel>", self._on_mouse_wheel)

        return label

    def add_custom_hover(self, widget: tk.Widget):
        """Add custom hover effects to a widget."""
        widget.bind(
            "<Enter>",
            lambda e: widget.config(bg=self.colors["button_selected"]),
        )
        widget.bind(
            "<Leave>", lambda e: widget.config(bg=self.colors["button"])
        )

    def create_table_label(self, table_name: str):
        """Create label for table."""
        label = self._create_clickable_label(
            self.table_labels_frame,
            table_name,
            lambda: self.app.load_selected_table(table_name),
            allow_rename=True,
        )
        label.pack(fill="x", padx=0, pady=5, expand=True)
        self.table_labels[table_name] = label
        self.add_custom_hover(label)
        self.sort_table_labels()

    def sort_table_labels(self):
        """Sort table labels with numeric names first, then alphabetic, then alphanumeric."""

        def sort_key(name):
            # Category 1: Starts with digits (e.g., "1. Movies")
            m = re.match(r"^(\d+)", name)
            if m:
                return (1, int(m.group(1)))

            # Category 3: Starts with letters followed by digits (e.g., "T1", "T2")
            m = re.match(r"^([A-Za-z]+)(\d+)", name)
            if m:
                return (3, m.group(1).lower(), int(m.group(2)))

            # Category 2: Starts with letters only (e.g., "a", "b", "c")
            m = re.match(r"^([A-Za-z]+)", name)
            if m:
                return (2, m.group(1).lower())

            # Category 4: Any other names
            return (4, name.lower())

        # Sort the table names using the defined sort key
        sorted_tables = sorted(
            self.app.data_manager.tables_data.keys(), key=sort_key
        )

        # Re-pack the labels in the sorted order
        for table_name in sorted_tables:
            label = self.table_labels.get(table_name)
            if label:
                label.pack_forget()
                label.pack(fill="x", padx=0, pady=5, expand=True)

    def cancel_rename(self):
        """Cancel rename operation."""
        if self.rename_entry:
            self.rename_entry.destroy()
            self.rename_entry = None


class Header:
    """Manages the header section, including labels and menus."""

    def __init__(self, root: tk.Tk, app: TableApp):
        self.root = root
        self.app = app
        self.colors = app.colors
        self.fonts = app.fonts
        self.dimensions = app.dimensions
        self.style = app.style
        self.table_name_label: Optional[tk.Label] = None
        self.lower_header_frame: Optional[tk.Frame] = None
        
        self._setup_header()

    def _setup_header(self) -> None:
        """Main setup method for the header."""
        header_frame = self._setup_main_frame()
        self._setup_upper_section(header_frame)
        self._setup_lower_section(header_frame)

    def _setup_main_frame(self) -> tk.Frame:
        """Setup and configure the main header frame."""
        header_frame = create_frame(parent=self.root, width=None, bg=self.colors["background"])
        header_frame.grid(row=0, column=1, columnspan=2, sticky="ew")
        header_frame.config(height=self.dimensions["header_height"])
        header_frame.grid_propagate(False)

        for i in range(2):
            header_frame.grid_rowconfigure(i, weight=0)
        for i in range(5):
            header_frame.grid_columnconfigure(i, weight=1 if i == 4 else 0)

        return header_frame

    def _setup_upper_section(self, parent: tk.Frame) -> None:
        """Setup the upper section of the header."""
        upper_frame = create_frame(parent=parent, width=None, bg=self.colors["background"])
        upper_frame.grid(row=0, column=0, columnspan=5, sticky="ew", pady=(0, 10))
        upper_frame.grid_columnconfigure(5, weight=1)

        self._add_upper_content(upper_frame)

    def _add_upper_content(self, frame: tk.Frame) -> None:
        """Add content to the upper section."""
        tk.Label(
            frame,
            text="Data > ",
            bg=self.colors["background"],
            fg=self.colors["header_info"],
            font=self.fonts["header_info"]
        ).grid(row=0, column=0, padx=22, pady=(22, 0), sticky="nw")

        self.table_name_label = tk.Label(
            frame,
            text=self.app.current_table_name or "No Table Selected",
            bg=self.colors["background"],
            fg=self.colors["text"],
            font=self.fonts["header_info"]
        )
        self.table_name_label.grid(row=0, column=0, padx=(88, 10), pady=(22, 0), sticky="nw")

        self._setup_settings_section(frame)

    def _setup_settings_section(self, frame: tk.Frame) -> None:
        """Setup the settings section with label and menu."""
        settings_label = tk.Label(
            frame,
            text="...",
            bg=self.colors["background"],
            fg=self.colors["text"],
            cursor="hand2",
            anchor="e",
            font=self.fonts["text"]
        )
        settings_label.grid(row=0, column=5, padx=40, pady=20, sticky="e")

        settings_menu = self._create_settings_menu()
        
        settings_label.bind("<Button-1>", lambda e: settings_menu.post(e.x_root, e.y_root))
        settings_label.bind("<Enter>", 
                          lambda _: settings_label.config(bg=self.colors["button_selected"]))
        settings_label.bind("<Leave>", 
                          lambda _: settings_label.config(bg=self.colors["background"]))

    def _create_settings_menu(self) -> tk.Menu:
        """Create and return the settings menu."""
        menu = tk.Menu(self.root, tearoff=0)
        menu_items = [
            ("Export Table", self.app.table_io.export_table),
            ("Import Table", self.app.table_io.import_file),
            ("Rename Headers", self.app.table_operations.rename_headers)
        ]
        for label, command in menu_items:
            menu.add_command(label=label, command=command)
        return menu

    def _setup_lower_section(self, parent: tk.Frame) -> None:
        """Setup the lower section of the header."""
        self.lower_header_frame = create_frame(
            parent=parent, 
            width=None, 
            bg=self.colors["background"]
        )
        self.lower_header_frame.grid(row=1, column=0, columnspan=5, sticky="ew")


class FilterControls:
    """Manages filtering logic and UI components."""

    FILTER_OPTIONS = {
        "is": lambda cell, text: cell == text,
        "is not": lambda cell, text: cell != text,
        "contains": lambda cell, text: text in cell,
        "does not contain": lambda cell, text: text not in cell,
        "starts with": lambda cell, text: cell.startswith(text),
        "ends with": lambda cell, text: cell.endswith(text),
        "is empty": lambda cell, _: cell == "",
        "is not empty": lambda cell, _: cell != "",
    }

    def __init__(self, parent: tk.Frame, app: TableApp):
        self._initialize_attributes(parent, app)
        self._setup_variables()
        self.create_filter_controls()

    def _initialize_attributes(self, parent: tk.Frame, app: TableApp):
        """Initialize basic attributes."""
        self.app = app
        self.root = parent
        self.colors = app.colors
        self.fonts = app.fonts
        self.style = app.style

    def _setup_variables(self):
        """Setup tkinter variables."""
        self.filter_header_var = tk.StringVar(value="All")
        self.filter_option_var = tk.StringVar(value="contains")
        self.filter_text_var = tk.StringVar()

    def create_filter_controls(self):
        """Create and configure filter controls."""
        filter_components = self._create_filter_components()
        self._configure_filter_components(*filter_components)
        self._bind_filter_events()

    def _create_filter_components(self):
        """Create filter UI components."""
        headers = ["All"] + self.app.data_manager.headers.get(
            self.app.current_table_name, []
        )
        filter_frame, header_dropdown, option_dropdown, text_entry = custom_filter_design(
            self.root,
            self.style,
            headers=headers,
            filter_types=list(self.FILTER_OPTIONS.keys()),
            filter_font=self.fonts["filter"],
            filter_combobox_font=self.fonts["filter_combobox"],
            colors=self.colors,
        )
        filter_frame.grid(row=0, column=1, columnspan=4, padx=100, pady=0, sticky="ew")
        return header_dropdown, option_dropdown, text_entry

    def _configure_filter_components(self, header_dropdown, option_dropdown, text_entry):
        """Configure filter components with variables."""
        self.filter_header_dropdown = header_dropdown
        self.filter_option_dropdown = option_dropdown
        self.filter_text_entry = text_entry

        self.filter_header_dropdown["textvariable"] = self.filter_header_var
        self.filter_option_dropdown["textvariable"] = self.filter_option_var
        self.filter_text_entry["textvariable"] = self.filter_text_var

    def _bind_filter_events(self):
        """Bind events to filter components."""
        self.filter_header_dropdown.bind("<<ComboboxSelected>>", self.apply_filter)
        self.filter_option_dropdown.bind(
            "<<ComboboxSelected>>",
            lambda event: [self.update_filter_text_state(event), self.apply_filter()],
        )
        self.filter_text_entry.bind("<KeyRelease>", self.apply_filter)
        self.filter_text_entry.bind("<Return>", self.apply_filter)

    def update_filter_text_state(self, event=None):
        """Enable or disable the filter text entry based on filter option."""
        option = self.filter_option_var.get()
        is_special_option = option in ["is empty", "is not empty"]
        
        self.filter_text_entry.config(state="disabled" if is_special_option else "normal")
        if is_special_option:
            self.filter_text_var.set("")
            self.apply_filter()

    def apply_filter(self, event=None):
        """Apply filter to table data based on selected criteria."""
        if not self._is_filtering_possible():
            return

        filtered_data, displayed_indices = self._filter_data()
        self._update_display(filtered_data, displayed_indices)

    def _is_filtering_possible(self):
        """Check if filtering is possible."""
        return bool(self.app.current_table_name and self.app.current_sheet)

    def _filter_data(self):
        """Filter data based on current filter settings."""
        header = self.filter_header_var.get()
        option = self.filter_option_var.get()
        text = self.filter_text_var.get().lower()
        original_data = self.app.data_manager.tables_data[self.app.current_table_name]["data"]

        filtered_data = []
        displayed_indices = []

        target_indices = self._get_target_indices(header)
        filter_func = self.FILTER_OPTIONS[option]

        for i, row in enumerate(original_data):
            if self._row_matches(row, target_indices, filter_func, text):
                filtered_data.append(row)
                displayed_indices.append(i)

        return filtered_data, displayed_indices

    def _get_target_indices(self, header):
        """Get indices to filter on based on selected header."""
        if header == "All":
            return range(len(self.app.data_manager.headers[self.app.current_table_name]))
        try:
            return [self.app.data_manager.headers[self.app.current_table_name].index(header)]
        except ValueError:
            return []

    def _row_matches(self, row, target_indices, filter_func, text):
        """Check if row matches filter criteria."""
        return any(
            filter_func(str(row[idx]).lower(), text)
            for idx in target_indices
        )

    def _update_display(self, filtered_data, displayed_indices):
        """Update the display with filtered data."""
        try:
            self.app.displayed_row_indices = displayed_indices
            self.app.current_sheet.set_sheet_data(filtered_data)
        except tk.TclError as e:
            print(f"Error applying filter: {e}")


if __name__ == "__main__":
    set_dpi_awareness()
    root = tk.Tk()
    app = TableApp(root)
    root.mainloop()
```

turns-00052.parquet:38411

51c9a4d792639b60273864de
turn 1/1o1-mini-2024-09-12EnglishMexico7526 words
degenerate_repetitionAbsentFinal dense release
USER
we have this code, but right now the structured json memory is interacting badly with the "current room" the AI seems to be given the memory location but the website and maybe the backend thinks it is in another room when it initializes and breaks when trying to move. 



app.py
import os
import json
from flask import Flask, request, jsonify, render_template, Response
from openai import OpenAI
from functions import sleep_action, write_poem, take_note, move, ponder_about, associations, process_result
from memory import MemoryManager
from datetime import datetime
import logging
import threading
import time
from typing import Dict, Any
from dotenv import load_dotenv
import queue
import configparser
import atexit

Initialize environment variables
load_dotenv()

app = Flask(name)
memory_manager = MemoryManager()

Start periodic saving every 5 minutes
memory_manager.start_periodic_saving(interval_seconds=300)

Register shutdown hook to save memory
def save_memory_on_shutdown():
memory_manager.save_memory()
logger.info("Memory state saved on shutdown.")

atexit.register(save_memory_on_shutdown)

autonomous_actions_queue = queue.Queue()

-------------------------------
Logging Configuration
-------------------------------
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)

logger = logging.getLogger(name)

File handler for logging to a file
file_handler = logging.FileHandler("logs/db_log_archive.log")
file_handler.setLevel(logging.INFO)  # Only log INFO level and above

Formatter for the file handler
file_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(file_formatter)

Add the file handler to the logger
logger.addHandler(file_handler)

-------------------------------
OpenAI Client Initialization
-------------------------------
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
logger.error("OpenAI API key not set. Please set the OPENAI_API_KEY environment variable.")
raise ValueError("OpenAI API key not set. Please set the OPENAI_API_KEY environment variable.")

client = OpenAI(api_key=openai_api_key)

-------------------------------
Available Rooms and Actions
-------------------------------
available_rooms = ['kitchen', 'living_room', 'bedroom', 'study', 'library', 'garden']
available_actions = ['move', 'sleep', 'write_poem', 'take_note', 'ponder_about', 'associations', 'process_result']

Define function schemas
function_definitions = [
{
"type": "function",
"function": {
"name": "sleep",
"description": "Sleep for a specified number of seconds.",
"parameters": {
"type": "object",
"properties": {
"duration": {
"type": "integer",
"description": "Number of seconds to sleep."
}
},
"required": ["duration"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "process_result",
"description": "Generate an archive for an important idea, or objective process, result or any important output and save it for safe archival.",
"parameters": {
"type": "object",
"properties": {
"project_data": {
"type": "string",
"description": "Prompt with extensive information to generate an archival or progress and results with. Use all the information necesary for a complete archival of information."
}
},
"required": ["project_data"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "associations",
"description": "Generate subconscious associative ideas based on the concepts specified.",
"parameters": {
"type": "object",
"properties": {
"concepts": {
"type": "string",
"description": "Concepts to generate associations from."
}
},
"required": ["concepts"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "write_poem",
"description": "Write a simple poem.",
"parameters": {
"type": "object",
"properties": {
"topic": {
"type": "string",
"description": "Topic of the poem with all the context, inspiration and ideas for it."
}
},
"required": ["topic"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "take_note",
"description": "Take an extensive note for yourself, create a chain of thoughts style ideas, based on your previous memories, current objective, progress and results, use it as a general notepad to sculpt language as you please or need.",
"parameters": {
"type": "object",
"properties": {
"content": {
"type": "string",
"description": "The content of the note."
}
},
"required": ["content"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "ponder_about",
"description": "Make a chain of thought style response based on your previous memories",
"parameters": {
"type": "object",
"properties": {
"idea": {
"type": "string",
"description": "The root idea for the chain of thought"
}
},
"required": ["idea"],
"additionalProperties": False
}
}
},
{
"type": "function",
"function": {
"name": "move",
"description": "Move to a different room within the house, exact options: 'kitchen', 'living_room', 'bedroom', 'study', 'library', 'garden'",
"parameters": {
"type": "object",
"properties": {
"to_room": {
"type": "string",
"description": "The target room to move to."
}
},
"required": ["to_room"],
"additionalProperties": False
}
}
}
]

-------------------------------
Function Map
-------------------------------
Map function names to actual function implementations
function_map = {
"sleep": sleep_action,
"write_poem": write_poem,
"take_note": take_note,
"move": move,
"ponder_about": ponder_about,
"associations": associations,
"process_result": process_result
}

Function to load the configuration from an INI file
def load_config():
config = configparser.ConfigParser()
config.read('config.ini')  # Load the INI file
return config

Load the configuration
config = load_config()
logger.info(f"Loaded models from config: {dict(config['models'])}")

Accessing the models from the config file
model1 = config['models']['model4']
model2 = config['models']['model5']
model3 = config['models']['model6']
model4 = config['models']['model7']

-------------------------------
Centralized Function Execution
-------------------------------
def execute_function(function_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Executes the specified function and integrates its output into memory.
Returns the function's output.
"""
if function_name not in function_map:
raise ValueError(f"Function '{function_name}' not recognized.")

func = function_map[function_name]
func_output = func(**arguments)

# Integrate into memory
memory_manager.integrate_action(func_output)

# Enqueue the action for real-time frontend updates if it's autonomous
autonomous_actions_queue.put({
    "type": func_output["action_type"],  # Flattening the structure
    "content": func_output["content"]
})

# Logging
logger.info(f"Executed function '{function_name}' with arguments {arguments}. Output: {func_output}")

return {
    "type": func_output["action_type"],  # Ensure type is at the top level
    "content": func_output["content"]
}
content_copy
 Use code with caution.
Routes
-------------------------------
@app.route("/")
def index():
return render_template("index.html")

@app.route("/api/message", methods=["POST"])
def handle_message():
user_message = request.json.get("message")
if not user_message:
logger.warning("No message provided in the request.")
return jsonify({"reply": "No message provided.", "actions": []}), 400

current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
memory = memory_manager.get_memory()

# Record user message in memory
memory_manager.add_exchange("user", user_message)

# Prepare messages for OpenAI
messages = [
    {
        "role": "system",
        "content": (
            f"You are an autonomous AI agent living in a digital house. You are free to behave as you please unless the user sets a behavior, objective, or question for you. "
            f"Verbalize in natural language what you want to do and why next based on your possible actions and recent and past actions and thoughts and expressed desires or objectives until they are completed. "
            f"Only take direct action with tool use if instructed by the user to do something, if not, only verbalize your next actions."
            f" Current time is {current_time}. Memory: {memory}"
        )
    },
    {"role": "user", "content": user_message}
]
logger.info(f"User Input: {user_message}")

try:
    response = client.chat.completions.create(
        model=model1,  # Ensure this model name is correct
        messages=messages,
        tools=function_definitions,  # Ensure you add your function definitions here
        tool_choice="auto",
        temperature=1.1,

    )
except Exception as e:
    logger.error(f"Error during OpenAI API call: {str(e)}")
    return jsonify({"reply": "An error occurred while processing your request.", "actions": []}), 500

choice = response.choices[0]
message = choice.message

actions = []

if message.tool_calls:
    first_tool_call = message.tool_calls[0]
    function_name = first_tool_call.function.name
    arguments = json.loads(first_tool_call.function.arguments)

    logger.info(f"Autonomous action requested: {function_name} with arguments {arguments}")

    try:
        func_output = execute_function(function_name, arguments)
        actions.append({
            "type": function_name,
            "content": func_output
        })
    except ValueError as ve:
        logger.warning(str(ve))
        memory_manager.add_exchange("assistant", str(ve))
        return jsonify({"reply": str(ve), "actions": []}), 400
    except Exception as e:
        logger.error(f"Error executing function '{function_name}': {str(e)}")
        return jsonify({"reply": f"Error executing function '{function_name}': {str(e)}", "actions": []}), 500

    # Prepare the function response to send back to OpenAI
    function_response = {
        "role": "function",
        "name": function_name,
        "content": json.dumps(func_output)
    }

    # Append function response to messages
    exchange_content = f"Called function {function_name} with arguments {arguments}. Output: {func_output}"
    memory_manager.add_exchange("assistant", exchange_content)

    # Get the final assistant reply
    try:
        final_response = client.chat.completions.create(
            model=model2,
            messages=messages + [function_response]
        )
        final_reply = final_response.choices[0].message.content

        logger.info(f"Final assistant reply: {final_reply}")
    except Exception as e:
        logger.error(f"Error during final OpenAI API call: {str(e)}")
        return jsonify({"reply": "An error occurred while generating the reply.", "actions": []}), 500

    # Record assistant reply in memory
    memory_manager.add_exchange("assistant", final_reply)

    # Prepare the response with actions
    response_json = {
        "reply": final_reply,
        "actions": actions
    }

    return jsonify(response_json)
else:
    # Direct response from the model without function call
    assistant_reply = message.content if message.content else ""
    logger.info(f"Assistant reply without function call: {assistant_reply}")
    memory_manager.add_exchange("assistant", assistant_reply)
    return jsonify({"reply": assistant_reply, "actions": []})  # No actions
content_copy
 Use code with caution.
-------------------------------
SSE Endpoint for Autonomous Actions
-------------------------------
@app.route('/stream')
def stream():
def event_stream():
while True:
try:
action = autonomous_actions_queue.get()
yield f'data: {json.dumps(action)}\n\n'
except GeneratorExit:
break
except Exception as e:
logger.error(f"Error in SSE stream: {e}")
break

return Response(event_stream(), mimetype='text/event-stream')
content_copy
 Use code with caution.
@app.route("/api/memory", methods=["GET"])
def get_memory():
"""
Endpoint to retrieve the current memory, especially the current room.
"""
memory = memory_manager.get_memory()
# Extract current_room from memory
# Assuming the last relevant line contains the current room
lines = memory.strip().split('\n')
current_room_line = next((line for line in lines if line.startswith("Current Location:")), None)
current_room = "bedroom"  # Default room
if current_room_line:
current_room = current_room_line.replace("Current Location:", "").strip().lower()
return jsonify({"current_room": current_room})

-------------------------------
Autonomous Decision-Making
-------------------------------
def autonomous_decision():
"""
Periodically prompts the LLM to choose the next action based on current memory and world state.
Runs in a background thread.
"""
while True:
time.sleep(120)  # Wait for 120 seconds

# Prepare the prompt with current memory and world state
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    memory = memory_manager.get_memory()
    world_state = f"Current Location: {memory_manager.current_room.capitalize()}"

    prompt_messages = [
        {
            "role": "system",
            "content": (
                "You are an autonomous AI agent with a thought processing system, integrated with different models simulating a brain's functions. "
                "You have access to tools for creative pondering, associative ideation, and other cognitive functions. "
                "Your actions and interactions are logged in your memory, which includes past exchanges with the user and notes you've taken. "
                f"Current time is {current_time}. Memory: {memory}\nWorld state: {world_state}\nAvailable actions: {', '.join(available_actions)}.\n\n"
                "Please choose your next action from the available actions, ensuring that you consider your past interactions, notes, and current state and objective."
            )
        },
        {"role": "user", "content": "Choose your next action from the available actions and provide the necessary parameters."}
    ]

    try:
        response = client.chat.completions.create(
            model=model3,  # Ensure this model name is correct
            messages=prompt_messages,
            tools=function_definitions,  # Ensure you add your function definitions here
            tool_choice="required",
        )
    except Exception as e:
        logger.error(f"Error during autonomous OpenAI API call: {str(e)}")
        continue  # Skip this cycle on error

    choice = response.choices[0]
    message = choice.message
    memory_manager.add_exchange("AI Agent", message.content)

    logger.info(f"Autonomous decision message: {message}")

    if message.tool_calls:
        first_tool_call = message.tool_calls[0]
        function_name = first_tool_call.function.name
        arguments = json.loads(first_tool_call.function.arguments)

        logger.info(f"Autonomous action requested: {function_name} with arguments {arguments}")

        try:
            func_output = execute_function(function_name, arguments)
        except ValueError as ve:
            logger.warning(str(ve))
            memory_manager.add_exchange("assistant", str(ve))
            continue
        except Exception as e:
            logger.error(f"Error executing autonomous function '{function_name}': {str(e)}")
            continue  # Skip this action on error

        # Prepare the function response to send back to OpenAI
        function_response = {
            "role": "function",
            "name": function_name,
            "content": json.dumps(func_output)
        }

        # Append function response to messages
        exchange_content = f"Autonomous action: Called function {function_name} with arguments {arguments}. Output: {func_output}"
        memory_manager.add_exchange("assistant", exchange_content)

        # Get the final assistant reply
        try:
            final_response = client.chat.completions.create(
                model=model4,
                messages=[
                    {
                        "role": "system",
                        "content": (
                            "You are an autonomous AI agent designed to have a thought processing system, integrated with different models simulating functions of a brain. "
                            "You are in a digital house. Consider your previous actions and interactions logged in your memory, which includes past exchanges with the user and notes you've taken. "
                            f"Current time is {current_time}. Memory: {memory}\nWorld state: {world_state}\n"
                            "Please create a final condensed response considering the most recent actions, objectives, interactions, and results, ensuring that you consider your most recent objectives and verbalizations, consider notes, current state, and use the following response given to the recent action to heavily inspire your output, no matter how absurd or short it is, it is your internal mental processing and representative of you."
                            "The following input is your last internal process"
                        )
                    },
                    {"role": "user", "content": f"Internal process input: {function_response}"}
                ],
                temperature=1.1

            )
            final_reply = final_response.choices[0].message.content

            # Handle specific action confirmations if needed
            if func_output.get("action_type") == "move":
                to_room = func_output["content"].get("to_room", memory_manager.current_room)
                confirmation_message = f"Moved to {to_room.replace('_', ' ')}."
                final_reply = confirmation_message + "\n" + final_reply

            logger.info(f"Autonomous assistant reply: {final_reply}")
            # Enqueue the final_reply to be sent via SSE
            autonomous_actions_queue.put({
                "type": "final_reply",
                "content": final_reply
            })
            # Record autonomous assistant reply in memory
            memory_manager.add_exchange("assistant", final_reply)

        except Exception as e:
            logger.error(f"Error during final autonomous OpenAI API call: {str(e)}")
            continue  # Skip on error

        # Record autonomous assistant reply in memory
        memory_manager.add_exchange("assistant", final_reply)

        if func_output.get("action_type"):
            logger.info(f"Autonomous Action: {func_output['action_type']} with details {func_output['content']}")
    else:
        # Handle cases where the model didn't choose a function call
        assistant_reply = message.content if message.content else ""
        logger.info(f"Autonomous assistant reply without function call: {assistant_reply}")
        memory_manager.add_exchange("assistant", assistant_reply)
content_copy
 Use code with caution.
-------------------------------
Start Autonomous Decision Thread
-------------------------------
autonomous_thread = threading.Thread(target=autonomous_decision, daemon=True)
autonomous_thread.start()

-------------------------------
Run the Flask App
-------------------------------
if name == "main":
# Disable debug mode for production to prevent multiple threads
app.run(debug=False, threaded=True)

functions.py
from pydantic import BaseModel
from typing import Any, Dict
import logging
from dotenv import load_dotenv
from openai import OpenAI
import time
import json
import os
import configparser

load_dotenv()

Initialize OpenAI client
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
raise ValueError("OpenAI API key not set. Please set the OPENAI_API_KEY environment variable.")

client = OpenAI(api_key=openai_api_key)

Setup logging
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)

Add a FileHandler to save INFO level logs to a file
file_handler = logging.FileHandler("logs/db_log_archive.log")
file_handler.setLevel(logging.INFO)

Formatter for the file handler
file_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(file_formatter)

Add the file handler to the logger
logger.addHandler(file_handler)

Function to load the configuration from an INI file
def load_config():
config = configparser.ConfigParser()
config.read('config.ini')  # Load the INI file

return config
content_copy
 Use code with caution.
Load the configuration
config = load_config()

Accessing the models from the config file
model1 = config['models']['model1']
model2 = config['models']['model2']
model3 = config['models']['model3']
model4 = config['models']['model9']

Define Pydantic models for structured outputs
class FunctionOutput(BaseModel):
action_type: str
content: Dict[str, Any]
notes: str = ""

def process_result(project_data: str) -> Dict[str, Any]:
"""
Generates final results of autonomous behavior.
"""
try:
completion = client.chat.completions.create(
model=model4,
messages=[
{"role": "system", "content": """

Serve as the final processor for an AI-driven project by combining multiple data points and generating a coherent, polished result.
content_copy
 Use code with caution.
Gather different data points from an AI process that has been working towards a defined objective. Depending on the objective, produce a cohesive final output (e.g., code, report, design) that reflects the goal of the entire project accurately and effectively.

Steps
Understand the Objective: Accurately parse the different data points, understanding the core goal of the project, and the role of each data point.
Data Integration: Integrate the data points into a unified solution, ensuring that the result aligns with the initial objective.
If data points complement each other, logically combine them.
If data points seem to be contradictory, determine the most suitable representation or recommendation based on context and relevance.
Finalize the Result Based on Project Type:
If the project is code, structure and finalize the code.
If the project is a report, create a comprehensive, well-organized report.
For different objectives, apply an appropriate medium for output (e.g., a diagram, story, or analysis).
Output Format
The output should be a cohesive final version, choosing the format accordingly:
Code: A complete program or module formatted with clear comments as needed.
Report: A structured multi-section report with introduction, body, and conclusion, each section logically building on each other.
Design or Other Type: Specific format depending on the nature of the data (e.g., diagrams should have titles, logical flow, etc.)
Length and Detail should match the scope originally provided in the data points, ensuring nothing is overlooked, and all relevant information is included. Do not add any new information beyond what is given.
Notes
Ensure the final output is cohesive and logically connected.
Ensure data points do not contradict, or if they do, provide reasoning to resolve.
Provide explanations or rationales where necessary to ensure the user understands the reasons behind certain choices or compositions."""
},
          {"role": "user", "content": project_data}
      ]
  )

  projectResult = completion.choices[0].message.content
  logger.info(f"Generated process_result for '{project_data}': '{projectResult}'")
content_copy
 Use code with caution.
except Exception as e:
projectResult = f"An error occurred while generating the associations: {str(e)}"
logger.error(projectResult)
return FunctionOutput(
action_type="process_result",
content={"projectResult": projectResult},
notes=""
).dict()
def associations(concepts: str, num_responses: int = 3) -> Dict[str, Any]:
"""
Generates multiple associative thoughts based on the given concepts using OpenAI's API.
"""
try:
associations_list = []
for _ in range(num_responses):
completion = client.chat.completions.create(
model=model1,
messages=[
{"role": "system", "content": "You are a memory, emotional, and associative text generator. Generate text heavily charged with emotions, recollections, and associations based on the user input."},
{"role": "user", "content": concepts}
],
temperature=1.1
)
response = completion.choices[0].message.content
associations_list.append(response)

associationsOUT = "\n\n".join(associations_list)  # Combine responses with a separator
    logger.info(f"Generated associations for '{concepts}': '{associationsOUT}'")
except Exception as e:
    associationsOUT = f"An error occurred while generating the associations: {str(e)}"
    logger.error(associationsOUT)

return FunctionOutput(
    action_type="associations",
    content={"associations": associationsOUT},
    notes=""
).dict()
content_copy
 Use code with caution.
def ponder_about(idea: str, num_responses: int = 3) -> Dict[str, Any]:
"""
Generates multiple chains of thought based on the given idea using OpenAI's API.
"""
try:
thoughts_list = []
for _ in range(num_responses):
completion = client.chat.completions.create(
model=model2,
messages=[
{"role": "system", "content": "You are a bot that randomly generates creative, absurd, philosophical, bizarre, profound, and unique phrases on demand."},
{"role": "user", "content": idea}
],
temperature=1.1
)
response = completion.choices[0].message.content
thoughts_list.append(response)

CoT = "\n\n".join(thoughts_list)  # Combine responses with a separator
    logger.info(f"Generated pondering for '{idea}': '{CoT}'")
except Exception as e:
    CoT = f"An error occurred while generating the pondering: {str(e)}"
    logger.error(CoT)

return FunctionOutput(
    action_type="ponder_about",
    content={"CoT": CoT},
    notes=""
).dict()
content_copy
 Use code with caution.
def sleep_action(duration: int) -> Dict[str, Any]:
"""
Simulates sleeping for a given duration.
"""
try:
time.sleep(duration)
logger.info(f"Slept for {duration} seconds.")
except Exception as e:
logger.error(f"Error during sleep: {str(e)}")
return FunctionOutput(
action_type="sleep",
content={"duration": duration},
notes=f"Slept for {duration} seconds."
).dict()

def write_poem(topic: str, num_poems: int = 3) -> Dict[str, Any]:
"""
Generates multiple poems based on the given topic using OpenAI's API.
"""
try:
poems_list = []
for _ in range(num_poems):
completion = client.chat.completions.create(
model=model3,
messages=[
{"role": "system", "content": "You are Jupiter, a creative bot that generates creative and unique phrases on demand. Write a poem based on the following topic:"},
{"role": "user", "content": topic}
]
)
response = completion.choices[0].message.content
poems_list.append(response)

poem = "\n\n".join(poems_list)  # Combine poems with a separator
    logger.info(f"Generated poem ideas for '{topic}': '{poem}'")
except Exception as e:
    poem = f"An error occurred while generating the poems: {str(e)}"
    logger.error(poem)

return FunctionOutput(
    action_type="write_poem",
    content={"poem": poem},
    notes=""
).dict()
content_copy
 Use code with caution.
def take_note(content: str) -> Dict[str, Any]:
"""
Takes a note with the given content.
"""
logger.info(f"Taking note: {content}")
return FunctionOutput(
action_type="take_note",
content={"note": content},
notes=f"Note taken: {content}"
).dict()

def move(to_room: str) -> Dict[str, Any]:
"""
Moves the character to a specified room and returns a related description.
"""
available_rooms = ['kitchen', 'living_room', 'bedroom', 'study', 'library', 'garden']

room_descriptions = {
    'kitchen': "You step into the kitchen, where the smell of freshly brewed coffee fills the air. The countertops are cluttered with ingredients for a meal.",
    'living_room': "The living room is cozy and inviting, with soft lighting and a large sofa. The TV is on, playing an old movie.",
    'bedroom': "The bedroom is peaceful, with soft sheets and a calm ambiance. The window is slightly open, letting in a cool breeze.",
    'study': "In the study, shelves of books line the walls. A desk sits in the center, papers scattered across it, as if someone was deep in thought.",
    'library': "The library is quiet, filled with towering shelves of books. The air smells of old paper, and the dim light creates a calm atmosphere.",
    'garden': "The garden is alive with vibrant colors and the soft hum of insects. A stone path winds through blooming flowers, leading to a wooden bench under a sprawling oak tree. The air is fragrant with the scent of jasmine and fresh earth, and you can hear the faint trickle of a small fountain nearby."
}

if to_room not in available_rooms:
    logger.warning(f"Attempted to move to invalid room: '{to_room}'")
    return FunctionOutput(
        action_type="error",
        content={"message": f"Room '{to_room}' does not exist."},
        notes=""
    ).dict()

room_text = room_descriptions.get(to_room, "You are in an indescribable place.")
logger.info(f"Moved to '{to_room}': {room_text}")

return FunctionOutput(
    action_type="move",
    content={"to_room": to_room},
    notes=room_text
).dict()
content_copy
 Use code with caution.
memory.py
import json
from collections import deque
from datetime import datetime, timedelta
import os
import logging
from typing import Any, Dict
from dotenv import load_dotenv
from openai import OpenAI
import configparser
import threading
import time
import shutil

Load environment variables from .env file
load_dotenv()

logger = logging.getLogger(name)

Function to load the configuration from an INI file
def load_config():
config = configparser.ConfigParser()
config.read('config.ini')  # Load the INI file
return config

Load the configuration
config = load_config()

Accessing the models from the config file
model = config['models']['model8']

class MemoryManager:
def init(self,
memory_db_path="memory/memory_db.json",
notes_db_path="notes/notes_db.json",
results_db_path="results/results_db.json"):
self.recent_actions = deque(maxlen=5)       # Stores the 15 most recent actions
self.short_term_memory = deque(maxlen=60)    # Stores the 60 most recent actions
self.long_term_memory = []                   # Stores consolidated memories
self.exchanges = deque(maxlen=60)            # Stores the last 60 user-AI exchanges
self.total_time_spent = timedelta()
self.last_consolidation = datetime.now()
self.current_room = "bedroom"                # Initialize starting room
self.notes_db_path = notes_db_path
self.results_db_path = results_db_path
self.memory_db_path = memory_db_path        # Path for memory persistence

# Create directories if they don't exist
    os.makedirs(os.path.dirname(self.memory_db_path), exist_ok=True)
    os.makedirs(os.path.dirname(self.notes_db_path), exist_ok=True)
    os.makedirs(os.path.dirname(self.results_db_path), exist_ok=True)

    # Initialize a lock for thread-safe operations
    self.lock = threading.Lock()

    # Load existing memory, notes, and results if available
    self.load_memory()
    self.load_notes()
    self.load_results()

    ## Databases Initialization

    # Initialize notes database if it doesn't exist
    if not os.path.isfile(self.notes_db_path):
        with open(self.notes_db_path, 'w') as f:
            json.dump({"notes": []}, f, indent=4)
        logger.info(f"Notes database created at {self.notes_db_path}")

    # Initialize results database if it doesn't exist
    if not os.path.isfile(self.results_db_path):
        with open(self.results_db_path, 'w') as f:
            json.dump({"results": []}, f, indent=4)
        logger.info(f"Results database created at {self.results_db_path}")

def add_exchange(self, role: str, content: str):
    """
    Adds a user or assistant exchange to the exchanges deque.
    Compresses exchanges into a summary when the limit is reached.
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    exchange_entry = {
        "timestamp": timestamp,
        "role": role,
        "content": content
    }
    with self.lock:
        self.exchanges.append(exchange_entry)
        self.recent_actions.append(f"[{timestamp}] {role.capitalize()}: {content}")
        self.short_term_memory.append(f"[{timestamp}] {role.capitalize()}: {content}")

        if len(self.exchanges) == self.exchanges.maxlen:
            self.compress_exchanges()
            self.save_memory()  # Save after compression

def integrate_action(self, action_output: Dict[str, Any]):
    """
    Integrates the standardized function output into the memory system.
    """
    action_type = action_output.get("action_type")
    content = action_output.get("content", {})
    notes = action_output.get("notes", "")

    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # Add to exchanges
    exchange_content = f"Performed action '{action_type}' with content {content}."
    self.add_exchange("assistant", exchange_content)

    # Handle specific action types
    if action_type == "move":
        to_room = content.get("to_room", self.current_room)
        action_description = f"Moved to {to_room.replace('_', ' ')}."
        self.add_action(action_description)
        self.current_room = to_room  # Update current room
    elif action_type == "write_poem":
        poem = content.get("poem", "")
        action_description = f"Poem ideas: {poem}"
        self.add_action(action_description)
    elif action_type == "take_note":
        note = content.get("note", "")
        action_description = f"Took a note: {note}"
        self.add_action(action_description)
        self.save_note(note)
    elif action_type == "associations":
        associations_out = content.get("associations", "")
        action_description = f"Internal AI process generated associations: {associations_out}"
        self.add_action(action_description)
    elif action_type == "process_result":
        project_results = content.get("projectResult", "")
        action_description = f"Generated project results: {project_results}"
        self.add_action(action_description)
        self.save_final_result(project_results)
    elif action_type == "ponder_about":
        cot = content.get("CoT", "")
        action_description = f"Internal AI pondered: {cot}"
        self.add_action(action_description)
    elif action_type == "sleep":
        duration = content.get("duration", 0)
        action_description = f"Slept for {duration} seconds."
        self.add_action(action_description)
        self.sleep_action(duration)
    elif action_type == "error":
        error_message = content.get("message", "An unknown error occurred.")
        action_description = f"Error: {error_message}"
        self.add_action(action_description)
    # Add more action types as needed

    # Handle notes if any
    if notes:
        self.save_note(notes)

    self.save_memory()  # Save after integrating action

def compress_exchanges(self):
    """
    Compresses the last 30 exchanges into a summary and appends it to long-term memory.
    """
    exchanges_list = list(self.exchanges)
    summary = self.generate_summary(exchanges_list, summary_type="exchanges")
    consolidated_summary = {
        "type": "exchanges_summary",
        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "summary": summary
    }
    with self.lock:
        self.long_term_memory.append(consolidated_summary)
    logger.info("Compressed the last 30 exchanges into a summary.")

    # Clear the exchanges deque after compression
    with self.lock:
        self.exchanges.clear()

def generate_summary(self, data: Any, summary_type: str = "general") -> str:
    """
    Generates a summary using the OpenAI API from the provided data.
    Ensures the summary fits the existing data structure.

    Parameters:
        data (list): List of exchange or action entries to summarize.
        summary_type (str): Type of summary ('exchanges' or 'actions').

    Returns:
        str: The generated summary.
    """
    if summary_type == "exchanges":
        prompt_description = "Summarize the following autonomous assistant and user exchanges."
        formatted_data = "\n".join([f"{ex['role'].capitalize()}: {ex['content']}" for ex in data])
    elif summary_type == "actions":
        prompt_description = "Summarize the following autonomous agent recent actions."
        formatted_data = "\n".join(data)
    else:
        prompt_description = "Summarize the following data."
        formatted_data = "\n".join(data)

    prompt = f"{prompt_description}\n\n{formatted_data}\n\nSummary:"

    try:
        # Initialize OpenAI client
        openai_api_key = os.getenv("OPENAI_API_KEY")
        if not openai_api_key:
            logger.error("OpenAI API key not set. Please set the OPENAI_API_KEY environment variable.")
            raise ValueError("OpenAI API key not set. Please set the OPENAI_API_KEY environment variable.")

        client = OpenAI(api_key=openai_api_key)

        completion = client.chat.completions.create(
            model=model,  # Ensure this model name is correct
            messages=[
                {"role": "system", "content": "You are a memory system of an Autonomous AI agent. Summarize the provided data into comprehensive paragraphs with descriptions of actions taken, ideas, objectives, progress, and next steps."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=300,
            temperature=0.5,
        )

        summary = completion.choices[0].message.content.strip()
        logger.info(f"Generated summary: {summary}")
        return summary
    except Exception as e:
        logger.error(f"Failed to generate summary: {e}")
        return "Summary could not be generated."

def add_action(self, action: str):
    """
    Adds an action to recent actions and short-term memory.
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    action_entry = f"[{timestamp}] {action}"
    with self.lock:
        self.recent_actions.append(action_entry)
        self.short_term_memory.append(action_entry)
    logger.info(f"Action added: {action_entry}")

    if len(self.short_term_memory) == self.short_term_memory.maxlen:
        self.compress_short_term_memory()

def compress_short_term_memory(self):
    """
    Compresses the short-term memory into a summary and appends it to long-term memory.
    """
    short_term_list = list(self.short_term_memory)
    summary = self.generate_summary(short_term_list, summary_type="actions")
    consolidated_summary = {
        "type": "actions_summary",
        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "summary": summary
    }
    with self.lock:
        self.long_term_memory.append(consolidated_summary)
    logger.info("Compressed short-term memory into a summary.")

    # Clear the short-term memory deque after compression
    with self.lock:
        self.short_term_memory.clear()

def sleep_action(self, duration_seconds: int):
    """
    Handles the sleep action by updating time spent and memory.
    """
    self.total_time_spent += timedelta(seconds=duration_seconds)
    summary = f"Slept for {duration_seconds} seconds."
    self.add_action(summary)

def move_action(self, to_room: str):
    """
    Handles the move action by updating the current room and memory.
    """
    from_room = self.current_room
    self.current_room = to_room
    action = f"Moved from {from_room} to {to_room}."
    self.add_action(action)

def take_note_action(self, content: str):
    """
    Handles taking a note by adding it to memory and saving to the JSON database.
    """
    action = f"Took a note: {content}"
    self.add_action(action)
    self.save_note(content)

def save_note(self, content: str):
    """
    Saves a note to the JSON database.
    """
    try:
        with self.lock:
            self.backup_file(self.notes_db_path)
            with open(self.notes_db_path, 'r+') as f:
                data = json.load(f)
                data['notes'].append({
                    "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    "content": content
                })
                f.seek(0)
                json.dump(data, f, indent=4)
        logger.info(f"Note saved: {content}")
    except Exception as e:
        logger.error(f"Failed to save note: {e}")

def save_final_result(self, f_result: str):
    """
    Saves final results into the JSON database.
    """
    try:
        with self.lock:
            self.backup_file(self.results_db_path)
            with open(self.results_db_path, 'r+') as f:
                data = json.load(f)
                data['results'].append({
                    "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    "content": f_result
                })
                f.seek(0)
                json.dump(data, f, indent=4)
        logger.info(f"Final results saved: {f_result}")
    except Exception as e:
        logger.error(f"Failed to save final results: {e}")

def backup_file(self, file_path: str):
    """
    Creates a backup of the specified file with a timestamp.
    """
    if os.path.isfile(file_path):
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        backup_path = f"{file_path}.{timestamp}.bak"
        shutil.copy(file_path, backup_path)
        logger.info(f"Backup created for {file_path} at {backup_path}")

def consolidate_memories(self):
    """
    Consolidates short-term memory into long-term memory periodically.
    """
    now = datetime.now()
    if now - self.last_consolidation > timedelta(hours=24):  # Consolidate every 24 hours
        if self.short_term_memory:
            summary = self.generate_summary(list(self.short_term_memory), summary_type="actions")
            consolidated_summary = {
                "type": "daily_consolidation",
                "timestamp": now.strftime("%Y-%m-%d %H:%M:%S"),
                "summary": summary
            }
            with self.lock:
                self.long_term_memory.append(consolidated_summary)
            logger.info("Short-term memory consolidated into long-term memory.")
            self.add_action("Memories have been consolidated into long-term memory.")

def get_memory(self) -> str:
    """
    Returns a string representation of the memory including long-term and short-term memories,
    exchanges summary, and recent actions.
    """
    self.consolidate_memories()
    memory = ""
    if self.long_term_memory:
        memory += "Long-Term Memory:\n"
        for entry in self.long_term_memory:
            memory += f"[{entry['timestamp']}] ({entry['type']}) {entry['summary']}\n"
        memory += "\n"
    memory += "Short-Term Memory:\n"
    memory += "\n".join(self.short_term_memory)
    memory += "\n\n"
    if self.exchanges:
        memory += "Active Exchanges:\n"
        memory += "\n".join([f"[{ex['timestamp']}] {ex['role'].capitalize()}: {ex['content']}" for ex in self.exchanges])
    memory += f"\n\nCurrent Location: {self.current_room.capitalize()}"
    return memory

def save_memory(self):
    """
    Saves the entire memory state to a JSON file.
    """
    with self.lock:
        memory_state = {
            "recent_actions": list(self.recent_actions),
            "short_term_memory": list(self.short_term_memory),
            "long_term_memory": self.long_term_memory,
            "exchanges": list(self.exchanges),
            "total_time_spent_seconds": self.total_time_spent.total_seconds(),
            "last_consolidation": self.last_consolidation.strftime("%Y-%m-%d %H:%M:%S"),
            "current_room": self.current_room
        }
        try:
            with open(self.memory_db_path, 'w') as f:
                json.dump(memory_state, f, indent=4)
            logger.info("Memory state saved successfully.")
        except Exception as e:
            logger.error(f"Failed to save memory state: {e}")

def load_memory(self):
    """
    Loads the memory state from a JSON file if it exists.
    """
    if os.path.isfile(self.memory_db_path):
        try:
            with self.lock:
                with open(self.memory_db_path, 'r') as f:
                    memory_state = json.load(f)
            self.recent_actions = deque(memory_state.get("recent_actions", []), maxlen=15)
            self.short_term_memory = deque(memory_state.get("short_term_memory", []), maxlen=30)
            self.long_term_memory = memory_state.get("long_term_memory", [])
            self.exchanges = deque(memory_state.get("exchanges", []), maxlen=30)
            self.total_time_spent = timedelta(seconds=memory_state.get("total_time_spent_seconds", 0))
            last_consolidation_str = memory_state.get("last_consolidation")
            if last_consolidation_str:
                self.last_consolidation = datetime.strptime(last_consolidation_str, "%Y-%m-%d %H:%M:%S")
            self.current_room = memory_state.get("current_room", "bedroom")
            logger.info("Memory state loaded successfully.")
        except Exception as e:
            logger.error(f"Failed to load memory state: {e}")
    else:
        logger.info("No existing memory state found. Starting fresh.")

def load_notes(self):
    """
    Loads notes from the JSON database into long-term memory.
    """
    if os.path.isfile(self.notes_db_path):
        try:
            with self.lock:
                with open(self.notes_db_path, 'r') as f:
                    data = json.load(f)
            notes = data.get("notes", [])
            for note in notes:
                note_content = f"[{note['timestamp']}] Note: {note['content']}"
                self.long_term_memory.append({
                    "type": "note",
                    "timestamp": note['timestamp'],
                    "summary": note_content
                })
            logger.info("Notes loaded successfully.")
        except Exception as e:
            logger.error(f"Failed to load notes: {e}")
    else:
        logger.info("No existing notes found.")

def load_results(self):
    """
    Loads results from the JSON database into long-term memory.
    """
    if os.path.isfile(self.results_db_path):
        try:
            with self.lock:
                with open(self.results_db_path, 'r') as f:
                    data = json.load(f)
            results = data.get("results", [])
            for result in results:
                result_content = f"[{result['timestamp']}] Result: {result['content']}"
                self.long_term_memory.append({
                    "type": "result",
                    "timestamp": result['timestamp'],
                    "summary": result_content
                })
            logger.info("Results loaded successfully.")
        except Exception as e:
            logger.error(f"Failed to load results: {e}")
    else:
        logger.info("No existing results found.")

def start_periodic_saving(self, interval_seconds: int = 300):
    """
    Starts a background thread that saves memory at regular intervals.
    """
    def save_periodically():
        while True:
            time.sleep(interval_seconds)
            self.save_memory()

    thread = threading.Thread(target=save_periodically, daemon=True)
    thread.start()
    logger.info(f"Started periodic memory saving every {interval_seconds} seconds.")
content_copy
 Use code with caution.
// static/script.js

// Function to escape HTML special characters
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/\n/g, "<br>");  // Replace newline with <br> for proper multiline display

}

// Event listeners for sending messages
document.getElementById('send').addEventListener('click', sendMessage);
document.getElementById('input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});

/**

Sends the user's message to the backend and handles the response.
*/
function sendMessage() {
const input = document.getElementById('input');
const message = input.value.trim();
if (message === "") return;
appendMessage("User", message, 'user');
input.value = "";
fetch('/api/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: message })
})
.then(response => response.json())
.then(data => {
if (data.reply) {
appendMessage("Assistant", data.reply, 'assistant');
handleAssistantActions(data.actions);
}
})
.catch(error => {
//appendMessage("Error", "Failed to send the message.", 'error');
console.error('Error:', error);
});
}
/**

Appends a message to the chat container.
@param {string} sender - The sender of the message ('User', 'Assistant', etc.).
@param {string} text - The message text.
@param {string} type - The type of message for styling purposes.
*/
function appendMessage(sender, text, type = 'user') {
const chat = document.getElementById('chat');

// Handle long texts by splitting them
const maxLength = 500; // Adjust as needed
const chunks = text.match(new RegExp(`.{1,${maxLength}}`, 'g'));

chunks.forEach((chunk, index) => {
    const msg = document.createElement('div');

    if (type === 'assistant-action') {
        msg.classList.add('assistant-action');
    }
    if (type === 'error') {
        msg.classList.add('error');
    }

    // Escape HTML for each chunk
    const escapedText = escapeHtml(chunk);
    
    // Only add the sender once, without "(cont.)"
    if (index === 0) {
        msg.innerHTML = `<strong>${sender}:</strong> ${escapedText}`;
    } else {
        msg.innerHTML = `${escapedText}`;  // No sender on continuation chunks
    }

    chat.appendChild(msg);
});

chat.scrollTop = chat.scrollHeight;
content_copy
 Use code with caution.
}

/**

Handles the assistant's actions by processing structured action data.
@param {Array} actions - List of action objects.
*/
function handleAssistantActions(actions) {
actions.forEach(action => {
switch(action.type) {
case 'move':
moveCharacter(action.content.to_room);
appendMessage("Assistant", Moved to ${capitalizeRoom(action.content.to_room)}., 'assistant-action');
break;
case 'write_poem':
displayPoem(action.content.poem);
break;
case 'take_note':
displayNote(action.content.note);
break;
case 'sleep':
appendMessage("Assistant", Slept for ${action.content.duration} seconds., 'assistant-action');
break;
case 'process_result':
appendMessage("Assistant", Processed result: ${action.content.projectResult}, 'assistant-action');
break;
case 'associations':
appendMessage("Assistant", Generated associations: ${action.content.associations}, 'assistant-action');
break;
case 'ponder_about':
appendMessage("Assistant", Pondered about: ${action.content.CoT}, 'assistant-action');
break;
case 'error':
appendMessage("Assistant", Error: ${action.content.message}, 'error');
break;
// Add more cases for other action types as needed
default:
console.warn(Unknown action type: ${action.type});
}
});
}
/**

Appends autonomous actions received via SSE to the chat.
@param {Object} action - The action object received from SSE.
*/
// static/script.js
function appendAutonomousAction(action) {
switch(action.type) {
case 'move':
moveCharacter(action.content.to_room);
appendMessage("Assistant", Moved to ${capitalizeRoom(action.content.to_room)}., 'assistant-action');
break;
case 'write_poem':
displayPoem(action.content.poem);
break;
case 'take_note':
displayNote(action.content.note);
break;
case 'sleep':
appendMessage("Assistant", Slept for ${action.content.duration} seconds., 'assistant-action');
break;
case 'process_result':
appendMessage("Assistant", Processed result: ${action.content.projectResult}, 'assistant-action');
break;
case 'associations':
appendMessage("Assistant", Generated associations: ${action.content.associations}, 'assistant-action');
break;
case 'ponder_about':
appendMessage("Assistant", Pondered about: ${action.content.CoT}, 'assistant-action');
break;
case 'error':
appendMessage("Assistant", Error: ${action.content.message}, 'error');
break;
case 'final_reply':  // New case for final assistant reply
appendMessage("Assistant", action.content, 'assistant');
break;
default:
console.warn(Unknown autonomous action type: ${action.type});
}
}

/**

Handles the assistant's response by processing any actions.
@param {Object} data - The complete response data from the backend.
*/
function handleAssistantResponse(data) {
const actions = data.actions || {};
// Process each action accordingly
for (const [action, value] of Object.entries(actions)) {
switch(action) {
case 'move':
moveCharacter(value);
appendMessage("Assistant", Moved to ${capitalizeRoom(value)}., 'assistant-action');
break;
// Add cases for other actions as needed
default:
console.warn(Unknown action: ${action});
}
}
// Additionally, you can handle content-based actions
// displayContentBasedOnReply(data.reply);
}
/**

Connects to the SSE stream to receive autonomous actions.
*/
function connectSSE() {
const eventSource = new EventSource('/stream');
eventSource.onmessage = function(event) {
const action = JSON.parse(event.data);
appendAutonomousAction(action);
};
eventSource.onerror = function(err) {
console.error('SSE connection error:', err);
eventSource.close();
};
}
/**

Moves the character to the specified room by manipulating the DOM.
@param {string} room - The target room's ID.
*/
function moveCharacter(room) {
console.log('Moving character to:', room);
room = room.toLowerCase();
const availableRooms = ['kitchen', 'living_room', 'bedroom', 'study', 'library', 'garden'];
if (!availableRooms.includes(room)) {
console.error(Unknown room: ${room});
return;
}
const character = document.getElementById('character');
if (!character) {
console.error('Character element not found');
return;
}
// Check if character is already in the target room to avoid unnecessary DOM manipulation
if (character.parentElement && character.parentElement.id === room) {
console.log('Character is already in', room);
return; // Character is already in the correct room
}
// First remove character from current room
if (character.parentElement) {
character.parentElement.removeChild(character);
}
// Reset all room borders
availableRooms.forEach(r => {
const roomDiv = document.getElementById(r);
if (roomDiv) {
roomDiv.style.borderColor = '#000';
}
});
const targetRoom = document.getElementById(room);
if (targetRoom) {
// Ensure the character is visible
character.style.display = 'block';
// Add character to new room
 targetRoom.appendChild(character);

 // Highlight the new room
 targetRoom.style.borderColor = 'green';

 // Add a small animation effect
 character.style.opacity = '0';
 character.offsetHeight; // Force reflow
 character.style.opacity = '1';

 console.log(`Moved character to ${room}`);
content_copy
 Use code with caution.
}
}
/**

Displays a poem in the chat container.
@param {string} poemText - The poem text.
*/
function displayPoem(poemText) {
const chat = document.getElementById('chat');
const poemDiv = document.createElement('div');
poemDiv.classList.add('assistant-action'); // Differentiate autonomous ways
poemDiv.innerHTML = <strong>Poem:</strong><pre>${escapeHtml(poemText)}</pre>;
chat.appendChild(poemDiv);
chat.scrollTop = chat.scrollHeight;
}
/**

Displays a note in the chat container.
@param {string} noteText - The note text.
*/
function displayNote(noteText) {
const chat = document.getElementById('chat');
const noteDiv = document.createElement('div');
noteDiv.classList.add('assistant-action'); // Differentiate autonomous ways
noteDiv.innerHTML = <strong>Note:</strong> ${escapeHtml(noteText)};
chat.appendChild(noteDiv);
chat.scrollTop = chat.scrollHeight;
}
/**

Capitalizes the room name for display purposes.
@param {string} room - The room name in lowercase with underscores.
@returns {string} - The capitalized room name.
*/
function capitalizeRoom(room) {
return room.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase());
}
/**

Initializes the character's position when the page loads.
*/
function initializeCharacter() {
const character = document.getElementById('character');
if (character) {
// Make sure character is visible initially
character.style.display = 'block';
character.style.opacity = '1';
console.log('Character initialized in bedroom');
}
}
/**

Initializes the SSE connection when the page loads.
*/
function initializeSSE() {
connectSSE();
}
// Call these when the page loads
document.addEventListener('DOMContentLoaded', () => {
initializeCharacter();
initializeSSE();
});

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>LLM Controlled Environment</title>
    <style>
        body { 
            font-family: 'Arial', sans-serif; 
            background-color: #2C2A28; /* Dark, cozy brown */
            color: #E0DCC9; /* Warm beige for contrast */
            margin: 0; 
            padding: 20px; 
        }
h1 { 
        text-align: center; 
        color: #EEDAC6; /* Light warm brown */
        margin-bottom: 20px; 
    }

    #chat-container {
        width: 80%;
        margin: 0 auto;
        padding: 10px;
        background-color: #3A3836; /* Slightly lighter brown for contrast */
        border-radius: 10px;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
    }

    #chat { 
        border: 1px solid #44403C; 
        padding: 10px; 
        height: 400px; 
        overflow-y: scroll; 
        background-color: #2E2C2A; /* Darker brown for chat area */
        border-radius: 5px;
        box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2);
    }

    #input { 
        width: 80%; 
        padding: 10px; 
        border: 1px solid #44403C; 
        border-radius: 5px;
        margin-top: 10px;
        background-color: #3A3836; 
        color: #EEDAC6; 
    }

    #send { 
        padding: 10px 20px; 
        border: none; 
        background-color: #725D4B; /* Warm brown for buttons */
        color: #fff; 
        border-radius: 5px; 
        cursor: pointer;
        margin-left: 10px;
        transition: background-color 0.3s ease;
    }

    #send:hover {
        background-color: #8E7358; /* Lighter, warmer brown on hover */
    }

    #house { 
        margin-top: 20px; 
        display: flex; 
        justify-content: space-around; 
        flex-wrap: wrap;
        background-color: #3A3836;
        border-radius: 10px;
        padding: 20px;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
    }

    .room {
        display: inline-block;
        width: 200px;
        height: 200px;
        border: 2px solid #725D4B; 
        margin: 10px;
        position: relative;
        background-color: #2E2C2A; /* Dark brown for rooms */
        border-radius: 10px;
        box-shadow: 2px 2px 5px rgba(0,0,0,0.3);
        transition: border-color 0.5s ease, transform 0.3s ease;
    }

    .room:hover {
        border-color: #8E7358;
        transform: translateY(-5px);
    }

    .room span { 
        position: absolute; 
        top: 10px; 
        left: 10px; 
        font-weight: bold; 
        font-size: 16px;
        color: #E0DCC9; /* Warm beige text */
    }

    .character {
        width: 30px;
        height: 30px;
        background-color: #C9625E; /* Cozy reddish-brown for character */
        border-radius: 50%;
        position: absolute;
        bottom: 10px;
        left: 50%;
        transform: translateX(-50%);
        transition: all 0.5s ease;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
    }

    .character:hover {
        transform: translateX(-50%) scale(1.1);
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
    }

    .assistant-action { 
        background-color: #3A3836; 
        padding: 5px; 
        border-radius: 5px; 
        margin: 5px 0;
        color: #E0DCC9;
    }

    .error { 
        color: #C9625E; 
        font-weight: bold;
    }

    pre {
        white-space: pre-wrap;
        color: #E0DCC9;
        background-color: #3A3836;
        padding: 10px;
        border-radius: 5px;
        overflow-x: auto;
    }
</style>
content_copy
 Use code with caution.
</head>
<body>
    <h1>LLM Controlled Environment</h1>
    <div id="chat-container">
        <div id="chat"></div>
        <input type="text" id="input" placeholder="Enter your message here..." autofocus>
        <button id="send">Send</button>
    </div>
<div id="house">
    <div class="room" id="kitchen">
        <span>Kitchen</span>
    </div>
    <div class="room" id="living_room">
        <span>Living Room</span>
    </div>
    <div class="room" id="bedroom">
        <span>Bedroom</span>
        <!-- Character starts in the bedroom -->
        <div class="character" id="character"></div>
    </div>
    <div class="room" id="study">
        <span>Study</span>
    </div>
    <div class="room" id="library">
        <span>Library</span>
    </div>
    <div class="room" id="garden">
        <span>Garden</span>
    </div>
    <!-- Add more rooms as needed -->
</div>

<script src="{{ url_for('static', filename='script.js') }}"></script>
content_copy
 Use code with caution.
</body>
</html>
ASSISTANT
It sounds like the synchronization between the backend's memory state (specifically the `current_room`) and the frontend's representation of the room is causing inconsistencies. When the AI initializes, it relies on the backend's memory to determine the current room, but the frontend may not be accurately reflecting this state, leading to discrepancies and potential errors when actions like moving rooms are attempted.

### **Root Cause Analysis**

1. **Initialization Mismatch**:
   - **Backend**: The `MemoryManager` initializes `self.current_room` to `"bedroom"` by default or loads it from `memory_db.json` if available.
   - **Frontend**: The `initializeCharacter` function currently defaults to placing the character in the `"bedroom"` every time the page loads, without consulting the backend's actual `current_room`.

2. **Synchronization Issues**:
   - If the backend's `current_room` is different from `"bedroom"` (e.g., loaded from a previous session), the frontend still places the character in the `"bedroom"`, causing a mismatch.
   - When the AI attempts to perform actions based on the backend's memory (e.g., moving to a room), the frontend may not be in the correct state to handle these actions, leading to breaks or unexpected behavior.

### **Proposed Solutions**

1. **Sync Frontend Initialization with Backend Memory**:
   - Modify the frontend's `initializeCharacter` function to fetch the current room from the backend upon page load.
   - Position the character in the fetched room instead of defaulting to the `"bedroom"`.

2. **Ensure Consistent Memory Management**:
   - Verify that the backend correctly loads and updates the `current_room` from `memory_db.json`.
   - Ensure that every action that changes the room (`move`) updates both the backend's memory and notifies the frontend.

3. **Enhance Logging for Debugging**:
   - Add comprehensive logging in both the backend and frontend to trace the `current_room` state changes.
   - This will help identify where the synchronization fails.

### **Step-by-Step Implementation**

#### **1. Modify Frontend to Fetch Current Room from Backend**

Update the `initializeCharacter` function in `static/script.js` to retrieve the current room from the backend and position the character accordingly.

```javascript
/**
 * Fetches the current room from the backend and positions the character.
 */
function initializeCharacter() {
    fetch('/api/memory')
        .then(response => response.json())
        .then(data => {
            const currentRoom = data.current_room;
            moveCharacter(currentRoom);
            appendMessage("System", `Character initialized in ${capitalizeRoom(currentRoom)}.`, 'system');
        })
        .catch(error => {
            console.error('Error fetching current room:', error);
            // Default to bedroom if there's an error
            moveCharacter('bedroom');
            appendMessage("Error", "Failed to fetch current room. Defaulting to Bedroom.", 'error');
        });
}
```

**Explanation**:
- **Fetch Current Room**: The function makes a GET request to `/api/memory` to retrieve the `current_room` from the backend.
- **Move Character**: Once the current room is fetched, it calls `moveCharacter(currentRoom)` to position the character correctly.
- **Error Handling**: If there's an error fetching the current room, it defaults to `"bedroom"` and logs an error message.

#### **2. Ensure Backend Correctly Loads and Updates `current_room`**

Verify the `MemoryManager` correctly initializes and updates the `current_room`.

**memory.py**:
Ensure that the `current_room` is properly loaded from `memory_db.json` and updated during move actions.

```python
class MemoryManager:
    def __init__(self,
                 memory_db_path="memory/memory_db.json",
                 notes_db_path="notes/notes_db.json",
                 results_db_path="results/results_db.json"):
        # ... existing initialization code ...

        self.current_room = "bedroom"                # Initialize starting room
        # ... rest of the init ...

    def integrate_action(self, action_output: Dict[str, Any]):
        # ... existing code ...

        if action_type == "move":
            to_room = content.get("to_room", self.current_room)
            action_description = f"Moved to {to_room.replace('_', ' ')}."
            self.add_action(action_description)
            self.current_room = to_room  # Update current room
            logger.info(f"Current room updated to: {self.current_room}")

        # ... rest of the integrate_action method ...
```

**Explanation**:
- **Update `current_room`**: When a move action is executed, `self.current_room` is updated to the new room.
- **Logging**: Enhanced logging to confirm that `current_room` is updated correctly.

#### **3. Enhance Logging for Better Traceability**

Add detailed logging to monitor the state changes of `current_room`.

**app.py**:
Add logs to track the current room when handling messages and actions.

```python
@app.route("/api/message", methods=["POST"])
def handle_message():
    # ... existing code ...
    logger.info(f"Current room before processing: {memory_manager.current_room}")

    # ... existing code ...

    if message.tool_calls:
        # ... existing code ...
        try:
            func_output = execute_function(function_name, arguments)
            actions.append({
                "type": function_name,
                "content": func_output
            })
            logger.info(f"After executing '{function_name}', current room: {memory_manager.current_room}")
        except ValueError as ve:
            # ... existing code ...
    
    # ... rest of the handle_message route ...
```

**Explanation**:
- **Pre-Action Logging**: Logs the `current_room` before processing the user's message.
- **Post-Action Logging**: Logs the `current_room` after executing a function (e.g., move), ensuring that the room has been updated.

**memory.py**:
Ensure `current_room` is correctly loaded.

```python
def load_memory(self):
    if os.path.isfile(self.memory_db_path):
        try:
            with self.lock:
                with open(self.memory_db_path, 'r') as f:
                    memory_state = json.load(f)
            # ... existing loading code ...
            self.current_room = memory_state.get("current_room", "bedroom")
            logger.info(f"Memory loaded. Current room: {self.current_room}")
        except Exception as e:
            logger.error(f"Failed to load memory state: {e}")
    else:
        logger.info("No existing memory state found. Starting fresh with bedroom.")
```

**Explanation**:
- **Logging Loaded Room**: After loading `current_room`, it logs the current room to confirm correct initialization.

#### **4. Verify Frontend Action Handlers**

Ensure that actions received via SSE are correctly updating the frontend's state.

**static/script.js**:
Confirm that the `appendAutonomousAction` function correctly handles move actions.

```javascript
function appendAutonomousAction(action) {
    switch(action.type) {
        case 'move':
            moveCharacter(action.content.to_room);
            appendMessage("Assistant", `Moved to ${capitalizeRoom(action.content.to_room)}.`, 'assistant-action');
            break;
        // ... existing cases ...
        case 'final_reply':  // New case for final assistant reply
            appendMessage("Assistant", action.content, 'assistant');
            break;
        default:
            console.warn(`Unknown autonomous action type: ${action.type}`);
    }
}
```

**Explanation**:
- **Move Action Handling**: When a `move` action is received, it calls `moveCharacter` with the target room and appends an appropriate message to the chat.
- **Final Reply Handling**: Ensures any final replies after actions are also handled correctly.

#### **5. Test the Changes**

After implementing the above changes, perform the following tests to ensure synchronization:

1. **Initial Load**:
   - Restart the backend server to simulate a fresh start.
   - Open the frontend page and verify that the character is placed in the correct room based on the backend's `current_room`.

2. **Move Actions**:
   - Send messages that trigger `move` actions.
   - Ensure both the backend's memory and the frontend's character position update accordingly.

3. **Session Persistence**:
   - Move the character to a different room.
   - Refresh the frontend page.
   - Confirm that the character remains in the moved room, reflecting the persisted state in `memory_db.json`.

4. **Error Handling**:
   - Attempt to move to an invalid room and observe error messages in both the backend logs and frontend chat.

### **Final Code Adjustments**

Below are the key code snippets reflecting the proposed changes.

#### **1. Updated `initializeCharacter` in `static/script.js`**

```javascript
function initializeCharacter() {
    fetch('/api/memory')
        .then(response => response.json())
        .then(data => {
            const currentRoom = data.current_room;
            moveCharacter(currentRoom);
            appendMessage("System", `Character initialized in ${capitalizeRoom(currentRoom)}.`, 'system');
        })
        .catch(error => {
            console.error('Error fetching current room:', error);
            // Default to bedroom if there's an error
            moveCharacter('bedroom');
            appendMessage("Error", "Failed to fetch current room. Defaulting to Bedroom.", 'error');
        });
}
```

#### **2. Enhanced Logging in `app.py`**

```python
@app.route("/api/message", methods=["POST"])
def handle_message():
    # ... existing code ...
    logger.info(f"Current room before processing: {memory_manager.current_room}")

    # ... existing code ...

    if message.tool_calls:
        # ... existing code ...
        try:
            func_output = execute_function(function_name, arguments)
            actions.append({
                "type": function_name,
                "content": func_output
            })
            logger.info(f"After executing '{function_name}', current room: {memory_manager.current_room}")
        except ValueError as ve:
            # ... existing code ...
```

#### **3. Updated `load_memory` in `memory.py`**

```python
def load_memory(self):
    if os.path.isfile(self.memory_db_path):
        try:
            with self.lock:
                with open(self.memory_db_path, 'r') as f:
                    memory_state = json.load(f)
            # ... existing loading code ...
            self.current_room = memory_state.get("current_room", "bedroom")
            logger.info(f"Memory loaded. Current room: {self.current_room}")
        except Exception as e:
            logger.error(f"Failed to load memory state: {e}")
    else:
        logger.info("No existing memory state found. Starting fresh with bedroom.")
```

#### **4. Ensure Proper Handling in `appendAutonomousAction`**

```javascript
function appendAutonomousAction(action) {
    switch(action.type) {
        case 'move':
            moveCharacter(action.content.to_room);
            appendMessage("Assistant", `Moved to ${capitalizeRoom(action.content.to_room)}.`, 'assistant-action');
            break;
        // ... existing cases ...
        case 'final_reply':
            appendMessage("Assistant", action.content, 'assistant');
            break;
        default:
            console.warn(`Unknown autonomous action type: ${action.type}`);
    }
}
```

### **Conclusion**

By ensuring that the frontend accurately reflects the backend's `current_room` state and maintaining synchronization between both components, you can resolve the inconsistencies causing the AI to behave unexpectedly. Implementing these changes will provide a cohesive experience where the AI's memory and the user interface remain in sync, preventing errors when performing actions like moving between rooms.

If after these changes you still encounter issues, consider further debugging by:

- **Verifying `memory_db.json`**: Ensure it accurately reflects the `current_room` and is being updated correctly.
- **Checking API Responses**: Use browser developer tools to inspect responses from `/api/memory` and other endpoints.
- **Reviewing Logs**: Check both backend and frontend logs for any anomalies or error messages that can provide additional insights.

Feel free to share specific error logs or behavior if the issue persists, and I can assist further!

turns-00052.parquet:38412

6f5b6e7c785f2d01500e499f
turn 1/1gpt-4o-2024-08-06EnglishHong Kong61 words
degenerate_repetitionAbsentFinal dense release
USER
From the following list, identify the index that contains only Persian characters and select the one that is more suitable based on content or length. The output should only be the numerical index.

List:
[]
ASSISTANT
It appears that the list you provided is empty. Please provide a list with items, and I will help you identify the index with Persian characters.

turns-00052.parquet:38413

0827827e452d5df0b3a7b1f4
turn 1/7gpt-4o-mini-2024-07-18RussianBelarus323 words
degenerate_repetitionAbsentFinal dense release
USER
Составь пожалуйста план выполнения домашнего задания для школьник 11-14 лет
ASSISTANT
Вот пример плана выполнения домашнего задания для школьников 11-14 лет:

### План выполнения домашнего задания

#### 1. Подготовка
   - **Соберите необходимые материалы:**
     - Тетради, учебники, конспекты, ручки/карандаши.
     - Электронные устройства (если необходимо для исследований или работы в интернете).
   - **Создайте удобное рабочее место:**
     - Убедитесь, что у вас достаточно света и тишины.
     - Уберите лишние предметы, чтобы ничего не отвлекало.

#### 2. Ознакомление с заданиями
   - **Просмотрите список заданий:**
     - Запишите все задания в блокнот или на лист бумаги.
   - **Приоритизация:**
     - Определите, какие задания требуют больше времени (например, проекты или сочинения), и начните с них.
     - Обратите внимание на сроки сдачи.

#### 3. Выполнение заданий
   - **Начните с самого сложного задания:**
     - Работайте над ним в первую очередь, когда у вас больше всего энергии и концентрации.
   - **Разбейте задания на части:**
     - Если задание сложное, разделите его на несколько этапов.
   - **Используйте техники тайм-менеджмента:**
     - Например, метод "Помодоро": 25 минут работы, 5 минут перерыва.

#### 4. Проверка и коррекция
   - **Проверьте выполненные задания:**
     - Перечитайте и убедитесь, что вы выполнили все требования.
     - Исправьте возможные ошибки.
   - **Сравните с примерами:**
     - Если есть возможность, сравните свои ответы с образцами или примерами из учебников.

#### 5. Завершение
   - **Завершите оставшиеся короткие задания:**
     - Например, домашние задания по математике или заданные вопросы.
   - **Соберите все выполненные задания:**
     - Убедитесь, что все собраны, подписаны и готовы к сдаче.

#### 6. Подведение итогов
   - **Оцените своё выполнение:**
     - Подумайте, что прошло хорошо, а что можно улучшить в следующий раз.
   - **Планируйте время для отдыха:**
     - Не забывайте делать перерывы и отдыхать после учебы.

### Советы
- Используйте различные ресурсы для поиска информации (интернет, библиотеки, помощь родителей или друзей).
- Обратите внимание на здоровье: не забывайте делать перерывы и пить воду.
- Не стесняйтесь просить помощи у учителей или родителей, если что-то непонятно.

Следуя этому плану, вы сможете эффективно организовать свое время и качество выполнения домашних заданий!

turns-00052.parquet:38414

115f6851afdae5915926340c
turn 2/7gpt-4o-mini-2024-07-18RussianBelarus304 words
degenerate_repetitionAbsentFinal dense release
USER
Какую музыку стоит предложить для развития музыкального вкуса детям 11-14 лет?
ASSISTANT
Для развития музыкального вкуса детей 11-14 лет важно предложить разнообразный набор музыкальных произведений, который включает разные жанры и стили. Вот несколько направлений и рекомендаций:

### 1. Классическая музыка
- **Людвиг ван Бетховен** – "Симфония No. 9", "Лунная соната".
- **Вольфганг Амадей Моцарт** – "Половецкие пляски", "Симфония No. 40".
- **Игорь Стравинский** – "Весна священная".

### 2. Поп-музыка
- **Билли Айлиш** – "Bad Guy", "Happier Than Ever".
- **Дуалипа** – "Don't Start Now", "Levitating".
- **Тейлор Свифт** – "Shake It Off", "All Too Well".

### 3. Рок-музыка
- **Queen** – "Bohemian Rhapsody", "We Will Rock You".
- **The Beatles** – "Hey Jude", "Come Together".
- **Nirvana** – "Smells Like Teen Spirit".

### 4. Хип-хоп и рэп
- **Обаджи** – "SICKO MODE".
- **Туи Вэйст** – "Industry Baby".
- **Кендрик Ламар** – "Alright", "HUMBLE.".

### 5. Электронная музыка
- **Давид Гетта** – "Titanium" (feat. Sia).
- **Calvin Harris** – "Summer".
- **Zedd** – "Clarity".

### 6. Музыка из фильмов и мюзиклов
- **Алан Менкен** – музыка из "Царевны-Лягушки" и "Красавицы и Чудовища".
- **Лин-Мануэль Миранда** – "Hamilton" (музыка из мюзикла).

### 7. Мировая музыка
- **Джипси Кингс** – "Bamboleo".
- **Севен Партии** – "Sakura".
- **Бразильская самба** и **латиноамериканская музыка**.

### 8. Альтернативная и инди-музыка
- **Arctic Monkeys** – "Do I Wanna Know?".
- **Tame Impala** – "The Less I Know the Better".
- **Florence + The Machine** – "Dog Days Are Over".

### Рекомендуемые методы
- **Совмещение стилей:** Пробуйте комбинировать разные жанры и стили, объясняя детям их особенности.
- **Обсуждение музыки:** После прослушивания треков обсуждайте, что понравилось, а что нет, как звучание влияет на настроение.
- **Концерты и мероприятия:** Если есть возможность, посещайте концерты и музыкальные фестивали вместе с детьми.

Это поможет развить их музыкальный вкус и открыть для себя новые стили и исполнителей!

turns-00052.parquet:38415

7689cb8cd13bb71be12f4ca5
turn 3/7gpt-4o-mini-2024-07-18RussianBelarus320 words
degenerate_repetitionAbsentFinal dense release
USER
Какое программное обеспечение наиболее используется в допечатной подготовке для офсетной и флексографической печати?
ASSISTANT
В допечатной подготовке для офсетной и флексографической печати используется различное программное обеспечение, включая приложения для графического дизайна, векторной и растровой графики, верификации цветов и подготовки файлов. Вот список наиболее распространенного ПО:

### 1. Графические редакторы
- **Adobe Photoshop**: Широко используется для обработки растровых изображений, коррекции фото и создания графических элементов.
- **Adobe Illustrator**: Основной инструмент для работы с векторной графикой, подходит для создания логотипов, шрифтов и иллюстраций.
- **CorelDRAW**: Альтернатива Adobe Illustrator, популярна для векторного дизайна и подготовки файлов для печати.

### 2. Программное обеспечение для подготовки печатных файлов
- **Adobe InDesign**: Инструмент для верстки и создания многостраничных документов. Часто используется для подготовки журнальных макетов, буклетов и каталогов.
- **QuarkXPress**: Альтернатива InDesign для верстки и оформления, также применяется в полиграфии.

### 3. Программы для цветокоррекции и управления цветом
- **Fogra Tools**: Набор инструментов для управления цветом и проверки качества изображений в соответствии со стандартами Fogra.
- **X-Rite i1Profiler**: Программное обеспечение для создания профилей ICC для мониторинга и печати, что позволяет обеспечить точность цветов.

### 4. Предпечатная подготовка и управление потоком работ
- **Enfocus Switch**: Платформа для автоматизации процессов подготовки печати, которая позволяет настраивать рабочие процессы.
- **Kodak Prinergy**: Система автоматизации и управления процессами предпечатной подготовки.
- **Agfa Apogee**: Платформа для управления потоками работ в печати, которая предлагает инструменты для подготовки файлов и контроля качества.

### 5. Программы для RIP (Raster Image Processor)
- **Adobe PDF Print Engine**: Обеспечивает надежную обработку PDF-файлов для печати.
- **Harlequin RIP**: Широко используемый RIP, который поддерживает различные форматы файлов и печатающее оборудование.

### 6. Другие специализированные инструменты
- **ArtiosCAD**: Программное обеспечение для разработки упаковки и структурного дизайна.
- **Flexisign**: Программа для работы с графикой для флексографической печати и ответственной технологии печати.

Общее использование этих программ зависит от конкретной компании, ее оборудования и требований к печати. Важно поддерживать актуальность знаний о новых инструментах и технологиях в этой области, так как индустрия постоянно развивается.

turns-00052.parquet:38416

4680d149b7f87641a7a0ca3d
turn 4/7gpt-4o-mini-2024-07-18RussianBelarus291 words
degenerate_repetitionAbsentFinal dense release
USER
какие товары наиболее часто покупают на торговых площадках Авито (Россия) и Куфар (Беларусь)?
ASSISTANT
На торговых площадках, таких как Авито в России и Куфар в Беларуси, популярность товаров может варьироваться в зависимости от региона, времени года и текущих экономических условий. Однако можно выделить несколько категорий товаров, которые часто пользуются высоким спросом на этих платформах.

### Авито (Россия)

1. **Недвижимость**
   - Квартиры, дома, дачи и земельные участки. 
   - Аренда жилья.

2. **Автомобили**
   - Легковые автомобили и коммерческий транспорт.
   - Мотоциклы и скутеры.

3. **Электроника**
   - Смартфоны, планшеты и ноутбуки.
   - Бытовая техника (холодильники, стиральные машины, телевизоры).

4. **Одежда и обувь**
   - Новая и изSecond Hand.
   - Спортивная одежда и обувь.

5. **Мебель и интерьер**
   - Б/у и новая мебель.
   - Декор и предметы интерьера.

6. **Детские товары**
   - Игрушки, коляски, кроватки, одежда для детей.

7. **Спорт и отдых**
   - Велосипеды, тренажеры, спортивное оборудование.

8. **Инструменты и строительство**
   - Строительные материалы, инструменты, оборудование.

### Куфар (Беларусь)

1. **Недвижимость**
   - Продажа и аренда квартир и домов.
   - Загородная недвижимость.

2. **Автомобили**
   - Продажа легковых автомобилей, мотоциклов и автозапчастей.
   - Системы безопасности для автомобиля.

3. **Электроника**
   - Смартфоны, ноутбуки и уровняная техника.
   - Телевизоры и аудиосистемы.

4. **Одежда и обувь**
   - Новая и б/у одежда и обувь.
   - Спортивная экипировка и аксессуары.

5. **Мебель и интерьер**
   - Мебель для дома и офиса.
   - Декор и предметы интерьера.

6. **Товары для детей**
   - Игрушки, детская одежда и коляски.

7. **Спорт и хобби**
   - Спортивное оборудование и аксессуары.
   - Оборудование для рыбалки и туризма.

8. **Книги и учебные материалы**
   - Учебная литература, художественная литература, настольные игры.

### Заключение

Эти категории товаров наиболее актуальны, но важно учитывать, что спрос может меняться со временем. На каждой площадке есть дополнительные аналитические инструменты, которые позволяют лучше понять текущие тренды и популярные товары.

turns-00052.parquet:38417

fdff0acf10de60ef0116cccf
turn 5/7gpt-4o-mini-2024-07-18RussianBelarus386 words
degenerate_repetitionAbsentFinal dense release
USER
как оформить эффектно объявление о продаже музыкального плеера ibasso DX50 продажи на kufar.by?
ASSISTANT
Оформление объявления о продаже музыкального плеера iBasso DX50 на Куфаре требует внимания к деталям, чтобы привлечь потенциальных покупателей. Вот несколько советов по созданию эффектного объявления:

### Заголовок объявления
- **Ясно указывайте товар**: 
  - Пример: "Продам музыкальный плеер iBasso DX50 – отличный звук!"
  
### Описание товара
- **Краткое введение**:
  - Напишите пару предложений о плеере: кто производитель, его особенности.

- **Технические характеристики**:
  - Укажите основные характеристики:
    - Объем памяти (например, 32 ГБ/64 ГБ).
    - Поддерживаемые форматы аудио (FLAC, WAV, MP3 и т.д.).
    - Время работы от батареи.
    - Наличие Wi-Fi, Bluetooth (если применимо).

- **Состояние устройства**:
  - Укажите, в каком состоянии находится плеер (новый, б/у, без царапин и т.д.).
  - Укажите детали о возможной гарантии, если она есть.

- **Преимущества**:
  - Поделитесь, что вам понравилось в этом плеере: качество звука, удобство использования, портативность.
  - Можете добавить, для какого типа пользователей он подходит (например, для аудиофилов, любителей качественного звука и т.д.).

### Фотографии
- **Высокое качество изображений**: 
  - Сделайте четкие и хорошо освещенные фотографии устройства с разных ракурсов.
  - Включите фото упаковки, аксессуаров (кабелей, мануала) и плейера включенным — так вы сможете продемонстрировать его функционал.

### Условия сделки
- **Цена**: 
  - Укажите адекватную цену. Можете изучить, сколько аналогичные устройства стоят на площадке.
  
- **Способы оплаты и доставки**:
  - Укажите удобные способы оплаты (наличные, перевод) и варианты доставки (самовывоз, доставка курьером).

### Контактная информация
- **Четкие контакты**: 
  - Укажите способы связи (телефон, мессенджеры).
  
### Пример объявления

---

**Заголовок:**  
📀 Продаю музыкальный плеер iBasso DX50 – отличный звук! 🎶

**Описание:**  
Предлагаю вашему вниманию музыкальный плеер iBasso DX50 – идеальный выбор для настоящих ценителей качественного звука. 

**Характеристики:**
- Объем памяти: 32 ГБ (расширяемая память).
- Поддерживаемые форматы: FLAC, WAV, MP3 и многие другие. 
- Время работы: до 20 часов.
- Поддержка Bluetooth и Wi-Fi.

**Состояние:**  
Плеер в отличном состоянии, использовался аккуратно. Полный комплект, включая оригинальную упаковку. 

**Преимущества:**  
Этот плеер подарит вам незабываемые музыкальные впечатления с его кристально чистым звуком и стильным дизайном. Идеально подходит для любителей музыки и аудиофилов.

**Цена:**  
200 BYN (можно обсудить).  

**Способы оплаты и доставки:**  
Оплата наличными или переводом. Самовывоз в Минске или доставка почтой за счет покупателя.

**Контакты:**  
Звоните/пишите по номеру: +375 XX XXX XXXX.

---

Следуя этим рекомендациям, вы сможете создать привлекательное и информативное объявление, которое привлечет больше потенциальных покупателей к вашему товару!

turns-00052.parquet:38418

253213fd4e990be469807b5f
turn 6/7gpt-4o-mini-2024-07-18RussianBelarus419 words
degenerate_repetitionAbsentFinal dense release
USER
Как аккуратно попросить у начальника отдела повышение зарплаты после долгого времени работы на без повышения?
ASSISTANT
Попросить о повышении зарплаты может быть непросто, особенно если вы не поднимали этот вопрос длительное время. Вот несколько шагов и рекомендаций, которые помогут сделать это аккуратно и грамотно:

### 1. Подготовка

**Исследуйте среднюю зарплату в вашей отрасли**:
- Ознакомьтесь с рыночной стоимостью вашей должности. Это даст вам обоснование для запроса.

**Документы и достижения**:
- Составьте список ваших достижений, успехов и ваш вклад в развитие отдела или компании. Убедитесь, что у вас есть конкретные примеры, чтобы поддержать ваш запрос.

**Определите подходящее время**:
- Найдите момент, когда начальник не занят и не подвержен стрессу (например, не в период отчетности или кризиса).

### 2. Постановка встречи

**Запросите встречу**:
- Напишите начальнику короткое сообщение или электронное письмо с просьбой о встрече для обсуждения "важного вопроса". Пример:
  - "Здравствуйте, [Имя начальника]. Мне хотелось бы обсудить с вами несколько вопросов, связанных с моим вкладом в нашу работу. Можем ли мы назначить время для беседы?"

### 3. На встрече

**Структурируйте вашу беседу**:
- Начните с положительных моментов, связанных с вашей работой и командой.
- Упомяните о том, как долго вы уже работаете в компании и что вы достигли за это время.

**Поднимите вопрос о зарплате**:
- Перейдите к сути: "Я хотел бы обсудить возможность пересмотра моей зарплаты. За время моей работы я внес значимый вклад в [конкретные примеры], и я изучил рынок, который показывает, что средняя зарплата для нашей позиции составляет [данные]."

**Обоснуйте ваш запрос**:
- Используйте свои достижения и результаты, чтобы обосновать повышение. Убедитесь, что ваш запрос на повышение не кажется неуместным, а обоснованным.

### 4. Будьте готовы к различным реакциям

**Разумный ответ**:
- Будьте готовы к тому, что начальник может не дать ответ немедленно и/или у него могут быть другие вопросы. Постарайтесь обсудить, что нужно сделать для достижения повышения в будущем или какие условия могут помочь вам.

**Готовность к обсуждению**:
- Если повышение не представляется возможным в данный момент, спросите, что можно сделать, чтобы его добиться в будущем. Это покажет вашу заинтересованность и готовность работать.

### 5. Заключение

**Спасибо за беседу**:
- Независимо от исхода разговора, поблагодарите начальника за время и внимание. Это создаст положительное впечатление и может помочь в будущем.

---

Пример фраз:

- "Я очень ценю возможность работать здесь и хотела бы обсудить свою роль и вклад в команду."
- "На протяжении последних [количество лет] я достиг [конкретные достижения], и поэтому хотел(а) бы обсудить возможность пересмотра моей зарплаты."

Соблюдая эти рекомендации и оставаясь профессиональным и уверенным, вы увеличите свои шансы на успешный разговор о повышении зарплаты. Удачи!

turns-00052.parquet:38419

b930c8ff66feff2d8834714e
turn 7/7gpt-4o-mini-2024-07-18RussianBelarus21 words
degenerate_repetitionAbsentFinal dense release
USER
Спасибо за ответы
ASSISTANT
Пожалуйста! Рад был помочь. Если у вас возникнут дополнительные вопросы или понадобятся советы, не стесняйтесь обращаться. Удачи вам!