mylesgoose commited on
Commit
a75702a
1 Parent(s): d056675

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +371 -0
README.md CHANGED
@@ -3,6 +3,377 @@ license: other
3
  license_name: other
4
  license_link: https://ai.meta.com/llama/license
5
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  Repairing the chat template for the model.
7
  There is a slight problem with the original llama 3.1 3.2 chat template. If you train a model with that current chat template and if the training script builds the prompts
8
  from a json file with the chat tempalte the model starts to output as its first token <|eot_id|><|start_header_id|>assistant<|end_header_id|> and naturally the script will then halt generation.
 
3
  license_name: other
4
  license_link: https://ai.meta.com/llama/license
5
  ---
6
+ to load the model you can do something like this, copy below to a python file and then run it. you must load an image and then type in the top by a message and hit enter.:
7
+ ```python
8
+ import torch
9
+ from datetime import date
10
+ from PIL import Image, ImageTk
11
+ from transformers import MllamaForConditionalGeneration, AutoProcessor
12
+ import tkinter as tk
13
+ from tkinter import filedialog, ttk, messagebox
14
+ import logging
15
+ import json
16
+ import os
17
+
18
+ # Configure logging
19
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
20
+
21
+ # Get today's date
22
+ date_string: str = date.today().strftime("%d %b %Y")
23
+ model_id = "mylesgoose/Llama-3.2-11B-Vision-Instruct"
24
+
25
+ # Load the model and processor
26
+ model = MllamaForConditionalGeneration.from_pretrained(
27
+ model_id,
28
+ torch_dtype=torch.bfloat16,
29
+ device_map="auto",
30
+ )
31
+ processor = AutoProcessor.from_pretrained(model_id)
32
+
33
+
34
+ class Application(tk.Frame):
35
+ def __init__(self, master=None):
36
+ super().__init__(master)
37
+ self.master = master
38
+ self.pack(fill="both", expand=True)
39
+ self.current_images = [] # Images for the current message
40
+ self.chat_sessions = {} # Dictionary to hold multiple chat sessions
41
+ self.active_session = "Session 1"
42
+ self.create_widgets()
43
+ self.update_status("Application started.")
44
+
45
+ def create_widgets(self):
46
+ # Create a style for ttk widgets
47
+ style = ttk.Style()
48
+ style.configure('TButton', font=('Helvetica', 10))
49
+ style.configure('TLabel', font=('Helvetica', 10))
50
+ style.configure('TNotebook.Tab', font=('Helvetica', 10))
51
+
52
+ # Create a menu bar
53
+ menu_bar = tk.Menu(self.master)
54
+ self.master.config(menu=menu_bar)
55
+
56
+ # Create the File menu
57
+ file_menu = tk.Menu(menu_bar, tearoff=0)
58
+ menu_bar.add_cascade(label="File", menu=file_menu)
59
+ file_menu.add_command(label="New Session", command=self.create_new_session)
60
+ file_menu.add_command(label="Load Session", command=self.load_chat_session)
61
+ file_menu.add_command(label="Save Session", command=self.save_current_chat)
62
+ file_menu.add_separator()
63
+ file_menu.add_command(label="Exit", command=self.on_closing)
64
+
65
+ # Create a Notebook for multiple sessions
66
+ self.notebook = ttk.Notebook(self)
67
+ self.notebook.pack(side="top", fill="both", expand=True)
68
+ self.notebook.bind("<<NotebookTabChanged>>", self.change_session)
69
+
70
+ # Initialize the first session
71
+ self.create_new_session()
72
+
73
+ # Status bar
74
+ self.status_bar = ttk.Label(self, text="Status: Ready", anchor="w")
75
+ self.status_bar.pack(side="bottom", fill="x")
76
+
77
+ def create_new_session(self, session_name=None):
78
+ if not session_name:
79
+ session_name = f"Session {len(self.chat_sessions) + 1}"
80
+ frame = ttk.Frame(self.notebook)
81
+ self.notebook.add(frame, text=session_name)
82
+ self.chat_sessions[session_name] = {
83
+ "frame": frame,
84
+ "chat_history": [],
85
+ "widgets": {}
86
+ }
87
+ self.active_session = session_name
88
+ self.build_session_widgets(frame, session_name)
89
+
90
+ def build_session_widgets(self, frame, session_name):
91
+ widgets = {}
92
+
93
+ # Text Entry
94
+ widgets['text_entry_label'] = ttk.Label(frame, text="Enter your message:")
95
+ widgets['text_entry_label'].pack(side="top", anchor="w", padx=10, pady=(10, 0))
96
+
97
+ widgets['text_entry'] = tk.Text(frame, height=5, width=80)
98
+ widgets['text_entry'].pack(side="top", fill="x", padx=10, pady=5)
99
+ widgets['text_entry'].bind("<Return>", self.generate_text_from_entry)
100
+
101
+ # Buttons Frame
102
+ widgets['buttons_frame'] = ttk.Frame(frame)
103
+ widgets['buttons_frame'].pack(side="top", fill="x", padx=10, pady=5)
104
+
105
+ widgets['load_image_button'] = ttk.Button(widgets['buttons_frame'], text="Load Image", command=self.load_image)
106
+ widgets['load_image_button'].pack(side="left", padx=5)
107
+
108
+ widgets['remove_image_button'] = ttk.Button(widgets['buttons_frame'], text="Remove Images", command=self.remove_images)
109
+ widgets['remove_image_button'].pack(side="left", padx=5)
110
+
111
+ widgets['generate_text_button'] = ttk.Button(widgets['buttons_frame'], text="Send", command=self.generate_text)
112
+ widgets['generate_text_button'].pack(side="left", padx=5)
113
+
114
+ widgets['reset_button'] = ttk.Button(widgets['buttons_frame'], text="Reset Chat", command=self.reset_chat)
115
+ widgets['reset_button'].pack(side="left", padx=5)
116
+
117
+ widgets['save_chat_button'] = ttk.Button(widgets['buttons_frame'], text="Save Chat", command=self.save_current_chat)
118
+ widgets['save_chat_button'].pack(side="left", padx=5)
119
+
120
+ # Chat History
121
+ widgets['chat_history_frame'] = ttk.Frame(frame)
122
+ widgets['chat_history_frame'].pack(side="top", fill="both", expand=True, padx=10, pady=5)
123
+
124
+ widgets['chat_history_canvas'] = tk.Canvas(widgets['chat_history_frame'])
125
+ widgets['chat_history_canvas'].pack(side="left", fill="both", expand=True)
126
+
127
+ widgets['chat_history_scrollbar'] = ttk.Scrollbar(widgets['chat_history_frame'], orient="vertical", command=widgets['chat_history_canvas'].yview)
128
+ widgets['chat_history_scrollbar'].pack(side="right", fill="y")
129
+
130
+ widgets['chat_history_canvas'].configure(yscrollcommand=widgets['chat_history_scrollbar'].set)
131
+ widgets['chat_history_container'] = ttk.Frame(widgets['chat_history_canvas'])
132
+ widgets['chat_history_canvas'].create_window((0, 0), window=widgets['chat_history_container'], anchor='nw')
133
+
134
+ widgets['chat_history_container'].bind("<Configure>", lambda event: widgets['chat_history_canvas'].configure(scrollregion=widgets['chat_history_canvas'].bbox("all")))
135
+
136
+ self.chat_sessions[session_name]['widgets'] = widgets
137
+
138
+ def change_session(self, event):
139
+ selected_tab = event.widget.select()
140
+ self.active_session = event.widget.tab(selected_tab, "text")
141
+ self.update_status(f"Switched to {self.active_session}")
142
+
143
+ def update_status(self, message):
144
+ self.status_bar.config(text=f"Status: {message}")
145
+ logging.info(message)
146
+
147
+ def load_image(self):
148
+ image_paths = filedialog.askopenfilenames()
149
+ for image_path in image_paths:
150
+ image = Image.open(image_path)
151
+ image.thumbnail((100, 100))
152
+ photo = ImageTk.PhotoImage(image)
153
+ label = tk.Label(self.chat_sessions[self.active_session]['widgets']['chat_history_container'], image=photo)
154
+ label.image = photo
155
+ label.pack(side="top", anchor="w", padx=5, pady=5)
156
+ self.current_images.append({'image': image, 'path': image_path})
157
+ self.update_status(f"Loaded {len(image_paths)} image(s).")
158
+
159
+ def remove_images(self):
160
+ self.current_images = []
161
+ self.update_status("All images removed from the current message.")
162
+
163
+ def generate_text(self, event=None):
164
+ user_text = self.chat_sessions[self.active_session]['widgets']['text_entry'].get("1.0", tk.END).strip()
165
+ if not user_text and not self.current_images:
166
+ self.update_status("Please enter a message or load images.")
167
+ return
168
+
169
+ # Display user's message and images in chat history
170
+ self.display_message("User", user_text, self.current_images)
171
+
172
+ session_data = self.chat_sessions[self.active_session]
173
+
174
+ # Prepare message content
175
+ message_content = []
176
+
177
+ if self.current_images:
178
+ message_content.append({"type": "image"})
179
+ # Add the text content
180
+ message_content.append({"type": "text", "text": user_text})
181
+
182
+ # Append the message to the chat history, including image paths
183
+ session_data['chat_history'].append({
184
+ "role": "user",
185
+ "content": message_content,
186
+ "images": [img['path'] for img in self.current_images] # Store image paths
187
+ })
188
+
189
+ # Build messages for the processor
190
+ messages = [{"role": message["role"], "content": message["content"]} for message in session_data['chat_history']] + \
191
+ [{"role": "system", "content": [{"You are a helpful and creative AI assistant."}]}]
192
+
193
+ try:
194
+ # Generate the input text for the processor
195
+ input_text = processor.apply_chat_template(messages, add_generation_prompt=True, date_string=date_string)
196
+
197
+ # Build all_images by collecting images from chat history
198
+ all_images = []
199
+ for message in session_data['chat_history']:
200
+ if 'images' in message and message['images']:
201
+ for img_path in message['images']:
202
+ try:
203
+ img = Image.open(img_path)
204
+ all_images.append(img)
205
+ except Exception as e:
206
+ logging.error(f"Error loading image {img_path}: {e}")
207
+ self.update_status(f"Error loading image {img_path}")
208
+
209
+ # Ensure the number of images matches the number of image tokens
210
+ total_image_tokens = input_text.count(processor.image_token)
211
+ if total_image_tokens != len(all_images):
212
+ self.update_status(f"Mismatch between image tokens ({total_image_tokens}) and images provided ({len(all_images)}).")
213
+ return
214
+
215
+ # Prepare inputs for the model
216
+ inputs = processor(images=all_images, text=input_text, return_tensors="pt").to(model.device)
217
+
218
+ # Generate the assistant's response
219
+ output = model.generate(**inputs, max_new_tokens=1000)
220
+ generated_text = processor.decode(output[0][inputs['input_ids'].shape[-1]:])
221
+
222
+ # Update chat history and UI with the assistant's response
223
+ session_data['chat_history'].append({
224
+ "role": "assistant",
225
+ "content": [{"type": "text", "text": generated_text}],
226
+ "images": []
227
+ })
228
+ self.display_message("Assistant", generated_text)
229
+
230
+ # Clear the text entry and current images
231
+ self.chat_sessions[self.active_session]['widgets']['text_entry'].delete("1.0", tk.END)
232
+ self.current_images = []
233
+
234
+ except Exception as e:
235
+ logging.error(f"Error during text generation: {e}")
236
+ self.update_status("An error occurred during text generation.")
237
+
238
+ def display_message(self, sender, text, images=[]):
239
+ container = self.chat_sessions[self.active_session]['widgets']['chat_history_container']
240
+ frame = ttk.Frame(container)
241
+ frame.pack(fill="x", pady=5)
242
+
243
+ label = ttk.Label(frame, text=f"{sender}:", font=('Helvetica', 10, 'bold'))
244
+ label.pack(side="top", anchor="w")
245
+
246
+ if images:
247
+ images_frame = ttk.Frame(frame)
248
+ images_frame.pack(side="top", fill="x")
249
+ for img_item in images:
250
+ if isinstance(img_item, dict):
251
+ img = img_item['image']
252
+ elif isinstance(img_item, str):
253
+ try:
254
+ img = Image.open(img_item)
255
+ except Exception as e:
256
+ logging.error(f"Error loading image {img_item}: {e}")
257
+ self.update_status(f"Error loading image {img_item}")
258
+ continue
259
+ else:
260
+ img = img_item
261
+ image = img.copy()
262
+ image.thumbnail((100, 100))
263
+ photo = ImageTk.PhotoImage(image)
264
+ img_label = ttk.Label(images_frame, image=photo)
265
+ img_label.image = photo
266
+ img_label.pack(side="left", padx=5)
267
+
268
+ message_label = ttk.Label(frame, text=text, wraplength=500, justify="left")
269
+ message_label.pack(side="top", anchor="w")
270
+
271
+ # Scroll to the bottom
272
+ canvas = self.chat_sessions[self.active_session]['widgets']['chat_history_canvas']
273
+ canvas.update_idletasks()
274
+ canvas.yview_moveto(1.0)
275
+
276
+ def generate_text_from_entry(self, event=None):
277
+ self.generate_text()
278
+ return "break" # Prevents the Text widget from inserting a newline
279
+
280
+ def reset_chat(self):
281
+ confirm = messagebox.askyesno("Reset Chat", "Are you sure you want to reset the chat?")
282
+ if confirm:
283
+ session_data = self.chat_sessions[self.active_session]
284
+ session_data['chat_history'] = []
285
+ self.current_images = []
286
+
287
+ # Clear chat history UI
288
+ container = session_data['widgets']['chat_history_container']
289
+ for widget in container.winfo_children():
290
+ widget.destroy()
291
+
292
+ self.update_status("Chat reset.")
293
+
294
+ def save_current_chat(self):
295
+ session_data = self.chat_sessions[self.active_session]
296
+ if not session_data['chat_history']:
297
+ messagebox.showinfo("Save Chat", "No chat history to save.")
298
+ return
299
+ filename = filedialog.asksaveasfilename(defaultextension=".json", initialfile=f"{self.active_session}.json", filetypes=[("JSON files", "*.json")])
300
+ if filename:
301
+ self.save_chat_history(filename)
302
+ self.update_status(f"Chat history saved to {filename}")
303
+
304
+ def save_chat_history(self, filename):
305
+ session_data = self.chat_sessions[self.active_session]
306
+ with open(filename, "w") as f:
307
+ json.dump(session_data['chat_history'], f)
308
+
309
+ def load_chat_session(self):
310
+ filename = filedialog.askopenfilename(defaultextension=".json", filetypes=[("JSON files", "*.json")])
311
+ if filename:
312
+ session_name = os.path.splitext(os.path.basename(filename))[0]
313
+ self.create_new_session(session_name)
314
+ self.load_chat_history(filename, session_name)
315
+ self.update_status(f"Chat session {session_name} loaded.")
316
+
317
+ def load_chat_history(self, filename, session_name):
318
+ with open(filename, "r") as f:
319
+ chat_history = json.load(f)
320
+ session_data = self.chat_sessions[session_name]
321
+ session_data['chat_history'] = chat_history
322
+ # Update UI with loaded chat history
323
+ for message in chat_history:
324
+ sender = message['role'].capitalize()
325
+ content = message['content']
326
+ images = []
327
+ if 'images' in message and message['images']:
328
+ images = message['images']
329
+ text = ""
330
+ for item in content:
331
+ if item.get('type') == 'text':
332
+ text = item.get('text', '')
333
+ break
334
+ self.display_message(sender, text, images)
335
+
336
+ def on_closing(self):
337
+ if messagebox.askokcancel("Quit", "Do you want to quit?"):
338
+ self.master.destroy()
339
+
340
+ root = tk.Tk()
341
+ root.title("LLM Chat Application")
342
+ app = Application(master=root)
343
+ root.protocol("WM_DELETE_WINDOW", app.on_closing)
344
+ app.mainloop()
345
+ ```
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+
377
  Repairing the chat template for the model.
378
  There is a slight problem with the original llama 3.1 3.2 chat template. If you train a model with that current chat template and if the training script builds the prompts
379
  from a json file with the chat tempalte the model starts to output as its first token <|eot_id|><|start_header_id|>assistant<|end_header_id|> and naturally the script will then halt generation.