1

class ChatGptResponseFrame(CTkScrollableFrame):
    def __init__(self, master, width, height, user_interface_instance, **kwargs):
        super().__init__(master, **kwargs)

        self.configure(width=width, height=height,
                       corner_radius=25, fg_color='#2b2d30')

        self.user_interface_class = user_interface_instance

    def get_openai_key(self):
        api_key = self.user_interface_class.api_key_auth_box.get_value()
        return api_key


class UserInterface(CTkFrame):
    """
    Represents the user interface for Windows Copilot (Modular).
    """

    def __init__(self, master, width, height, chat_gpt_response_instance, **kwargs):
        super().__init__(master, **kwargs)

        self.chat_gpt_class = chat_gpt_response_instance

        # Set the width and height of the frame
        self.configure(width=width, height=height,
                       corner_radius=25, fg_color='#222327',
                       border_color='#e9eef6', border_width=2)

        # Openai API Key Authentication Input Field
        self.api_key_auth_box = InputField(master=self,
                                           width=320,
                                           height=45,
                                           placeholder_text='Openai API Key')
        self.api_key_auth_box.get_place(relx=0.1, rely=0.2)

        # Authenticate Button
        self.run_button = Button(master=self,
                                 text='Authenticate',
                                 corner_radius=15,
                                 command=self.chat_gpt_class.get_openai_key)
        self.run_button.get_place(relx=0.64, rely=0.37)


class WindowsCopilot(CTk):
    def __init__(self):
        super().__init__()

        # App Configuration
        self.title("Windows Copilot (Modular)")
        self.geometry("460x580")  # 750x550
        set_appearance_mode("Dark")

        # User interface Instance
        self.ui_frame = UserInterface(self,
                                      width=400, height=300,
                                      user_interface_instance=self.chat_gpt_response_frame)
        # self.ui_frame.place(relx=0.5, rely=0.5, anchor="center")
        self.ui_frame.pack(padx=10, pady=(10, 10))

        # ChatGptResponseFrame Instance
        self.chat_gpt_response_frame = ChatGptResponseFrame(self,
                                                            width=370, height=300,
                                                            user_interface_instance=self.ui_frame)

        self.chat_gpt_response_frame.pack(padx=10, pady=(10, 10))


if __name__ == '__main__':
    app = WindowsCopilot()
    app.mainloop()

Description: I'm working on a modular chatbot interface called "Windows Copilot" using Python's Tkinter library. The application consists of three classes: ChatGptResponseFrame, UserInterface, and WindowsCopilot.

The ChatGptResponseFrame class inherits from CTkScrollableFrame and has a method get_openai_key() to retrieve an OpenAI API key from the UserInterface class.

The UserInterface class inherits from CTkFrame and contains an input field (api_key_auth_box) for the user to enter the API key and a button (run_button) to trigger the authentication process by calling the get_openai_key() method from the ChatGptResponseFrame instance.

The WindowsCopilot class inherits from CTk and represents the main application window. It sets up the window, creates instances of ChatGptResponseFrame and UserInterface, and packs the ChatGptResponseFrame instance into the window.

I'm encountering two main issues:

  1. AttributeError: When I run the code, I get the following error:
Traceback (most recent call last):
  File "main.py", line 88, in <module>
    app = WindowsCopilot()
          ^^^^^^^^^^^^^^^^
  File "main.py", line 73, in __init__
    user_interface_instance=self.chat_gpt_response_frame)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: '_tkinter.tkapp' object has no attribute 'chat_gpt_response_frame'

I believe the issue is related to the order of instance creation or referencing between the classes. How can I fix it? Any suggestions or insights would be highly appreciated.

  1. Widget Displacement: Additionally, when I swap the instances of ChatGptResponseFrame and UserInterface (e.g., creating ChatGptResponseFrame first and then UserInterface), the widgets get displaced within the application window. The layout get affected. How can I prevent this widget displacement and ensure a consistent layout when swapping instances? Any advice on how to manage the layout effectively would be very helpful.

I expect the code to run without any AttributeError, allowing me to interact with the chatbot interface smoothly. When I swap the instances, I want the UI elements to remain in their positions and not get displaced. Any insights, suggestions, or solutions to address these issues would be highly appreciated. Thank you!

Elie Hacen
  • 372
  • 12

1 Answers1

1

Step 1: Modify the ChatGptResponseFrame class to remove the circular reference issue by removing the user_interface_class_instance parameter.

class ChatGptResponseFrame(CTkScrollableFrame):
    def __init__(self, master, width, height, **kwargs):
        super().__init__(master, **kwargs)

        self.configure(width=width, height=height,
                       corner_radius=25, fg_color='#2b2d30')

        self.user_interface_class = None

    def get_openai_key(self):
        api_key = self.user_interface_class.api_key_auth_box.get_value()
        return api_key

Step 2: Modify the UserInterface class to remove the circular reference issue by removing the chat_gpt_response_instance parameter and adding the on_authenticate method to handle the button click event.

class UserInterface(CTkFrame):
    def __init__(self, master, width, height, **kwargs):
        super().__init__(master, **kwargs)

        self.chat_gpt_class = None

        # Set the width and height of the frame
        self.configure(width=width, height=height,
                       corner_radius=25, fg_color='#222327',
                       border_color='#e9eef6', border_width=2)

        # Openai API Key Authentication Input Field
        self.api_key_auth_box = InputField(master=self,
                                           width=320,
                                           height=45,
                                           placeholder_text='Openai API Key')
        self.api_key_auth_box.get_place(relx=0.1, rely=0.2)

        # Authenticate Button
        self.run_button = Button(master=self,
                                 text='Authenticate',
                                 corner_radius=15,
                                 command=self.on_authenticate)
        self.run_button.get_place(relx=0.64, rely=0.37)

    def on_authenticate(self):
        if self.chat_gpt_class is not None:
            api_key = self.get_openai_key()
            # Do something with the API key, e.g., pass it to the ChatGptResponseFrame
            print(api_key)

Step 3: Modify the WindowsCopilot class to create instances of both UserInterface and ChatGptResponseFrame, set the references correctly, and pack the frames in the desired order.

class WindowsCopilot(CTk):
    def __init__(self):
        super().__init__()

        # App Configuration
        self.title("Windows Copilot (Modular)")
        self.geometry("460x580")  # 750x550
        set_appearance_mode("Dark")

        # App Title Label
        title_label = CTkLabel(master=self,
                               text='WINDOWS COPILOT',
                               font=CTkFont(family='Courier', size=30, weight='bold'))
        title_label.pack(padx=10, pady=(30, 5))

        # User interface Instance
        self.ui_frame = UserInterface(self,
                                      width=400, height=300)

        # ChatGptResponseFrame Instance
        self.chat_gpt_response_frame = ChatGptResponseFrame(self,
                                                            width=370, height=300)

        # Set the chat_gpt_response_instance after creating both frames
        self.ui_frame.chat_gpt_class = self.chat_gpt_response_frame
        self.chat_gpt_response_frame.user_interface_class = self.ui_frame

        # Pack the frames
        self.ui_frame.pack(padx=10, pady=(10, 10))
        self.chat_gpt_response_frame.pack(padx=10, pady=(10, 10))
        

With these changes, the circular reference issue is resolved, and the code should run without any errors. Both the UserInterface and ChatGptResponseFrame instances are created correctly, and their references are set appropriately.

Elie Hacen
  • 372
  • 12