import tkinter as tk import customtkinter as ctk from llama_cpp import Llama import threading import os import sys # Set appearance and theme ctk.set_appearance_mode("Dark") ctk.set_default_color_theme("blue") class LlamaChatApp(ctk.CTk): def __init__(self, model_path): super().__init__() self.title("AI Chatbot - Llama-2-7B") self.geometry("1100x750") # Grid configuration (Sidebar + Main) self.grid_columnconfigure(1, weight=1) self.grid_rowconfigure(0, weight=1) # Sidebar self.sidebar_frame = ctk.CTkFrame(self, width=220, corner_radius=0) self.sidebar_frame.grid(row=0, column=0, sticky="nsew") self.sidebar_frame.grid_rowconfigure(4, weight=1) self.logo_label = ctk.CTkLabel(self.sidebar_frame, text="🦙 Llama AI", font=ctk.CTkFont(size=22, weight="bold")) self.logo_label.grid(row=0, column=0, padx=20, pady=(30, 20)) self.clear_button = ctk.CTkButton( self.sidebar_frame, text="New Chat", command=self.clear_chat, fg_color="#333333", hover_color="#444444", height=40, font=ctk.CTkFont(weight="bold") ) self.clear_button.grid(row=1, column=0, padx=20, pady=10, sticky="ew") # Theme Switcher self.theme_label = ctk.CTkLabel(self.sidebar_frame, text="Appearance:", font=ctk.CTkFont(size=11)) self.theme_label.grid(row=4, column=0, padx=20, pady=(20, 0), sticky="w") self.theme_option = ctk.CTkOptionMenu( self.sidebar_frame, values=["Dark", "Light"], command=self.change_appearance_mode, height=30, fg_color="#333333", button_color="#444444" ) self.theme_option.grid(row=5, column=0, padx=20, pady=(5, 10), sticky="ew") self.info_label = ctk.CTkLabel( self.sidebar_frame, text="Model: Llama-2-7B\nFormat: GGMLv3\nType: Offline LLM", font=ctk.CTkFont(size=11), text_color="#888888", justify="left" ) self.info_label.grid(row=6, column=0, padx=20, pady=20, sticky="w") # Main Content Area self.main_container = ctk.CTkFrame(self, corner_radius=0, fg_color="#0f0f0f") self.main_container.grid(row=0, column=1, sticky="nsew") self.main_container.grid_columnconfigure(0, weight=1) self.main_container.grid_rowconfigure(1, weight=1) # Header in Main Area self.header = ctk.CTkFrame(self.main_container, height=60, corner_radius=0, fg_color="#1a1a1a") self.header.grid(row=0, column=0, sticky="ew") self.header.grid_columnconfigure(0, weight=1) self.title_label = ctk.CTkLabel( self.header, text="Chat Session", font=ctk.CTkFont(size=18, weight="bold") ) self.title_label.grid(row=0, column=0, pady=20) # Chat display self.chat_display = ctk.CTkTextbox( self.main_container, state="disabled", wrap="word", font=ctk.CTkFont(size=15), fg_color="#0d0d0d", border_width=0, text_color="#e0e0e0" ) self.chat_display.grid(row=1, column=0, padx=30, pady=(20, 10), sticky="nsew") # Configure tags for coloring self.chat_display.tag_config("User", foreground="#3B82F6") # Blue self.chat_display.tag_config("Llama-2", foreground="#10B981") # Green self.chat_display.tag_config("System", foreground="#6B7280") # Grey # Input area container (for centered look) self.bottom_frame = ctk.CTkFrame(self.main_container, fg_color="transparent") self.bottom_frame.grid(row=2, column=0, padx=30, pady=(10, 20), sticky="ew") self.bottom_frame.grid_columnconfigure(0, weight=1) self.user_input = ctk.CTkEntry( self.bottom_frame, placeholder_text="Message Llama-2...", font=ctk.CTkFont(size=14), height=50, border_width=1, border_color="#333333", corner_radius=12, fg_color="#1a1a1a" ) self.user_input.grid(row=0, column=0, padx=(0, 10), sticky="ew") self.user_input.bind("", lambda e: self.send_message()) self.send_button = ctk.CTkButton( self.bottom_frame, text="Send", command=self.send_message, width=90, height=50, corner_radius=12, font=ctk.CTkFont(weight="bold") ) self.send_button.grid(row=0, column=1) # Status indicator self.status_container = ctk.CTkFrame(self.main_container, height=25, fg_color="transparent") self.status_container.grid(row=3, column=0, sticky="ew", padx=30, pady=(0, 10)) self.status_dot = ctk.CTkLabel(self.status_container, text="●", font=ctk.CTkFont(size=14), text_color="#f44336") self.status_dot.pack(side="left") self.status_text = ctk.CTkLabel(self.status_container, text="OFFLINE", font=ctk.CTkFont(size=11, weight="bold"), text_color="#888888") self.status_text.pack(side="left", padx=5) # LLM Logic self.model_path = model_path self.llm = None self.is_loading = True threading.Thread(target=self.init_model, daemon=True).start() def change_appearance_mode(self, new_mode): ctk.set_appearance_mode(new_mode) bg = "#0f0f0f" if new_mode == "Dark" else "#f5f5f5" chat_bg = "#0d0d0d" if new_mode == "Dark" else "#ffffff" text_col = "#e0e0e0" if new_mode == "Dark" else "#1a1a1a" header_bg = "#1a1a1a" if new_mode == "Dark" else "#ebebeb" self.main_container.configure(fg_color=bg) self.chat_display.configure(fg_color=chat_bg, text_color=text_col) self.header.configure(fg_color=header_bg) def init_model(self): try: self.llm = Llama(model_path=self.model_path, n_ctx=2048, n_threads=4, verbose=False) self.is_loading = False self.after(0, self.on_model_ready) except Exception as e: self.after(0, lambda: self.on_model_error(str(e))) def on_model_ready(self): self.status_dot.configure(text_color="#4CAF50") self.status_text.configure(text="ONLINE", text_color="#4CAF50") self.append_message("System", "Llama-2 is ready. Ask me anything!") def on_model_error(self, error): self.status_text.configure(text=f"ERROR: {error}", text_color="#f44336") self.append_message("System", "Failed to load model. Check path.") def clear_chat(self): self.chat_display.configure(state="normal") self.chat_display.delete("0.0", "end") self.chat_display.configure(state="disabled") if not self.is_loading: self.append_message("System", "Chat cleared. Starting new session.") def append_message(self, sender, message): self.chat_display.configure(state="normal") tag = sender if sender == "User": display_name = "👤 YOU" elif sender == "Llama-2": display_name = "🦙 LLAMA-2" else: display_name = "⚙️ SYSTEM" tag = "System" self.chat_display.insert("end", f"{display_name}\n", (tag,)) self.chat_display.insert("end", f"{message}\n\n") self.chat_display.configure(state="disabled") self.chat_display.see("end") def send_message(self): if self.is_loading: return msg = self.user_input.get().strip() if not msg: return self.user_input.delete(0, "end") self.append_message("User", msg) self.send_button.configure(state="disabled") self.status_text.configure(text="THINKING...", text_color="#FFA726") threading.Thread(target=self.generate_response, args=(msg,), daemon=True).start() def generate_response(self, message): try: prompt = f"[INST] <>\nYou are a helpful assistant.\n<>\n\n{message} [/INST]" output = self.llm(prompt, max_tokens=1024, stop=["[/INST]", ""], echo=False) response = output['choices'][0]['text'].strip() self.after(0, lambda: self.append_message("Llama-2", response)) self.after(0, lambda: self.status_text.configure(text="ONLINE", text_color="#4CAF50")) except Exception as e: self.after(0, lambda: self.append_message("System", f"Error: {str(e)}")) finally: self.after(0, lambda: self.send_button.configure(state="normal")) if __name__ == "__main__": MODEL_PATH = r"C:\Users\student\Downloads\llama-2-7b-chat.ggmlv3.q2_K.bin" if not os.path.exists(MODEL_PATH): print(f"Error: Model not found at {MODEL_PATH}") sys.exit(1) app = LlamaChatApp(MODEL_PATH) app.mainloop()