88THEME_PATH : str = os .path .join (APP_PATH , "theme" , "custom-theme.json" )
99ctk .set_default_color_theme (THEME_PATH )
1010
11- url = "http://localhost:11434/api/chat"
11+ # url = "http://localhost:11434/api/chat"
1212
1313model_list = [
1414 "llama3.1" ,
@@ -77,46 +77,106 @@ def setup_ui(self):
7777
7878 # top panel buttons
7979 top_frame = ctk .CTkFrame (self )
80- top_frame .grid (padx = 5 ,pady = 2 , sticky = "nswe" )
80+ top_frame .grid (row = 0 , padx = 5 ,pady = 2 , sticky = "nswe" )
8181 top_frame .configure (fg_color = "transparent" )
8282
83- #self.theme_button = ctk.CTkButton(top_frame, text="🌗Toogle theme",)
84- #self.theme_button.grid(row=0, column=1, padx=(0,3))
85- #self.theme_button.configure(height=20, font=("", 12), width=10)
86-
8783 self .gpl_button = ctk .CTkButton (top_frame , text = "GPL License" , command = self .open_gpl )
88- self .gpl_button .grid (row = 0 , column = 2 , padx = (0 ,3 ))
84+ self .gpl_button .grid (row = 0 , column = 0 , padx = (0 ,3 ))
8985 self .gpl_button .configure (height = 20 , font = ("" , 13 ), width = 10 , border_width = 0 )
9086
9187 self .model_menu_var = ctk .StringVar ()
9288 self .model_menu_var .set (model_list [0 ])
9389 self .model_menu_var .trace_add ("write" , self .on_model_change )
9490 self .model_menu = ctk .CTkOptionMenu (top_frame , variable = self .model_menu_var , values = model_list )
95- self .model_menu .grid (row = 0 , column = 3 , padx = (0 ,3 ), pady = (1 ,0 ))
91+ self .model_menu .grid (row = 0 , column = 1 , padx = (0 ,3 ), pady = (1 ,0 ))
9692 self .model_menu .configure (height = 23 , font = ("" , 12 ), dynamic_resizing = True ,)
9793
9894 self .custom_model_name = ctk .CTkEntry (top_frame ,)
99- self .custom_model_name .grid (row = 0 , column = 4 , padx = (0 ,3 ),)
100- self .custom_model_name .configure (height = 20 , font = ("" , 12 ), placeholder_text = "Custom model..." )
95+ self .custom_model_name .grid (row = 0 , column = 2 , padx = (0 ,3 ),)
96+ self .custom_model_name .configure (
97+ height = 20 ,
98+ font = ("" , 12 ),
99+ placeholder_text = "Custom model..."
100+ )
101+
102+ top_frame2 = ctk .CTkFrame (self )
103+ top_frame2 .grid (row = 0 , columnspan = 2 , padx = 5 , pady = 2 , sticky = "e" )
104+ top_frame2 .configure (fg_color = "transparent" )
105+
106+ self .host_url = ctk .CTkEntry (top_frame2 )
107+ self .host_url .grid (row = 0 , column = 0 , padx = (20 ,3 ), sticky = "e" )
108+ self .host_url .configure (
109+ height = 20 ,
110+ width = 230 ,
111+ font = ("" , 12 ),
112+ placeholder_text = "Host URL..."
113+ )
114+ self .host_url .insert (0 ,"http://localhost:11434" )
101115
102116 self .theme_var = ctk .StringVar (value = "off" )
103- self .theme_switch = ctk .CTkSwitch (self , text = "light/dark mode" , variable = self .theme_var , onvalue = "on" , offvalue = "off" , command = self .theme_modes )
104- self .theme_switch .grid (row = 0 , columnspan = 2 , padx = (0 ,5 ), sticky = "e" )
117+ self .theme_switch = ctk .CTkSwitch (
118+ top_frame2 ,
119+ text = "light/dark mode" ,
120+ variable = self .theme_var ,
121+ onvalue = "on" ,
122+ offvalue = "off" ,
123+ command = self .theme_modes ,
124+ )
125+ self .theme_switch .grid (row = 0 , column = 1 , padx = (0 ,5 ), sticky = "e" )
105126
106127 # mid panel
107128 self .chat_output = ctk .CTkTextbox (self , height = 600 )
108- self .chat_output .grid (row = 1 , columnspan = 2 , padx = 5 , pady = (5 ,2 ), sticky = "nsew" ,)
129+ self .chat_output .grid (
130+ row = 1 ,
131+ columnspan = 2 ,
132+ padx = 5 ,
133+ pady = (5 , 2 ),
134+ sticky = "nsew" ,
135+ )
109136 self .chat_output .configure (wrap = "word" , state = "disabled" ,
110137 font = ("" , 14 )
111138 )
112139
113- self .save_button = ctk .CTkButton (self , text = "💾" , command = self .save_chat )
114- self .save_button .grid (row = 2 , column = 0 , sticky = "e" , padx = 5 )
115- self .save_button .configure (height = 10 , width = 10 , corner_radius = 5 , hover_color = "#024f04" , border_width = 2 )
140+ mid_frame = ctk .CTkFrame (self )
141+ mid_frame .grid (row = 2 , columnspan = 2 , sticky = "e" )
142+ mid_frame .configure (fg_color = "transparent" )
143+
144+ mid_frame2 = ctk .CTkFrame (self )
145+ mid_frame2 .grid (row = 2 , sticky = "w" )
146+ mid_frame2 .configure (fg_color = "transparent" )
147+
148+ self .save_button = ctk .CTkButton (mid_frame , text = "💾" , command = self .save_chat )
149+ self .save_button .grid (row = 2 , column = 1 , padx = 5 ,)
150+ self .save_button .configure (
151+ height = 10 ,
152+ width = 10 ,
153+ corner_radius = 5 ,
154+ hover_color = "#024f04" ,
155+ border_width = 2
156+ )
157+
158+ self .clear_button = ctk .CTkButton (mid_frame , text = "💀" , command = self .clear_chat )
159+ self .clear_button .grid (row = 2 , column = 2 , padx = (0 ,5 ),)
160+ self .clear_button .configure (
161+ height = 10 ,
162+ width = 10 ,
163+ corner_radius = 5 ,
164+ hover_color = "#3b0103" ,
165+ border_width = 2
166+ )
116167
117- self .clear_button = ctk .CTkButton (self , text = "💀" , command = self .clear_chat )
118- self .clear_button .grid (row = 2 , column = 1 , sticky = "e" , padx = (0 ,5 ))
119- self .clear_button .configure (height = 10 , width = 10 , corner_radius = 5 , hover_color = "#3b0103" , border_width = 2 )
168+ self .autoscroll_var = ctk .StringVar (value = "on" )
169+ self .autoscroll_box = ctk .CTkCheckBox (
170+ mid_frame2 ,
171+ text = "Autoscroll" ,
172+ variable = self .autoscroll_var ,
173+ onvalue = "on" ,
174+ offvalue = "off" ,
175+ )
176+ self .autoscroll_box .grid (row = 2 , column = 0 , padx = 5 ,)
177+ self .autoscroll_box .configure (
178+ font = ("" , 12 ), checkbox_width = 18 , checkbox_height = 18
179+ )
120180
121181 # lower panel
122182 self .input_field = ctk .CTkTextbox (self , height = 100 )
@@ -126,9 +186,11 @@ def setup_ui(self):
126186
127187 self .send_button = ctk .CTkButton (self , text = "📤" , command = self .send_message )
128188 self .send_button .grid (row = 3 , column = 1 , sticky = "we" , padx = (0 ,5 ), pady = (5 ,5 ))
129- self .send_button .configure (height = 100 , width = 10 , corner_radius = 5 , border_width = 2 )
189+ self .send_button .configure (
190+ height = 100 , width = 10 , corner_radius = 5 , border_width = 2
191+ )
130192
131- self .copyright_label = ctk .CTkLabel (self , text = "Copyright (c) 2025 by Kamil Wiśniewski" )
193+ self .copyright_label = ctk .CTkLabel (self , text = "Copyright © 2025 by Kamil Wiśniewski | Ver. 1.4 " )
132194 self .copyright_label .grid (sticky = "se" , row = 4 , column = 0 , columnspan = 2 , padx = 5 )
133195 self .copyright_label .configure (font = ("" , 10 ))
134196
@@ -159,6 +221,13 @@ def insert_text(self, content):
159221 self .chat_output .insert ("end" , content )
160222 self .chat_output .configure (state = "disabled" )
161223
224+ try :
225+ if self .autoscroll_var .get () == "on" :
226+ self .chat_output .see ("end" )
227+
228+ except Exception as e :
229+ print (f"Error: { e } " )
230+
162231 def on_model_change (self , * args ):
163232 self .messages = []
164233 self .insert_text (f"\n Model changed to: { self .model_menu .get ()} \n \n " )
@@ -223,12 +292,14 @@ def send_message(self):
223292 "stream" : True
224293 }
225294
295+ url = f"{ self .host_url .get ().rstrip ('/api/chat' )} /api/chat"
296+
226297 try :
227298 response = requests .post (url , json = payload , stream = True )
228299
229300 if response .status_code == 200 :
230301 self .insert_text ("AI: " )
231- self .update ()
302+ # self.update()
232303
233304 # full_reply "", needed for AI to remember the context of messages.
234305 # Without this, every new message is considered as new chat or whatever.
0 commit comments