MishaGGG commited on
Commit
769a891
·
verified ·
1 Parent(s): c14bd6e

Upload 12 files

Browse files
GUIvdront.py ADDED
@@ -0,0 +1,649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import threading
4
+ import pygame
5
+ import torch
6
+ import torch.nn.functional as F
7
+ from transformers import GPT2TokenizerFast, GPT2Config
8
+ from safetensors.torch import load_file
9
+ from model import VDrontModel
10
+
11
+ # ------------------------------------------------------------
12
+ # Paths / constants
13
+ # ------------------------------------------------------------
14
+ MODEL_DIR = "./VDrontV3-Mini"
15
+ USER_TOKEN = "<|user|>"
16
+ ASSISTANT_TOKEN = "<|assistant|>"
17
+
18
+ WINDOW_WIDTH = 900
19
+ WINDOW_HEIGHT = 700
20
+ FPS = 60
21
+
22
+ # ------------------------------------------------------------
23
+ # Theme colors
24
+ # ------------------------------------------------------------
25
+ def get_theme_colors(theme: str):
26
+ if theme == "dark":
27
+ return {
28
+ "background": (25, 25, 30),
29
+ "surface": (38, 38, 46),
30
+ "surface_alt": (50, 50, 60),
31
+ "text": (230, 230, 235),
32
+ "text_secondary": (160, 160, 170),
33
+ "accent": (100, 140, 255),
34
+ "accent_hover": (130, 165, 255),
35
+ "border": (70, 70, 85),
36
+ "input_bg": (35, 35, 45),
37
+ "user_bubble": (70, 100, 200),
38
+ "user_text": (255, 255, 255),
39
+ "ai_bubble": (52, 52, 62),
40
+ "ai_text": (230, 230, 235),
41
+ "button": (50, 50, 60),
42
+ "button_hover": (70, 70, 85),
43
+ "danger": (200, 80, 80),
44
+ "success": (80, 180, 120),
45
+ }
46
+ else: # light
47
+ return {
48
+ "background": (240, 240, 245),
49
+ "surface": (255, 255, 255),
50
+ "surface_alt": (230, 230, 235),
51
+ "text": (30, 30, 35),
52
+ "text_secondary": (100, 100, 110),
53
+ "accent": (60, 90, 200),
54
+ "accent_hover": (90, 120, 230),
55
+ "border": (200, 200, 210),
56
+ "input_bg": (245, 245, 250),
57
+ "user_bubble": (100, 140, 240),
58
+ "user_text": (255, 255, 255),
59
+ "ai_bubble": (225, 225, 230),
60
+ "ai_text": (30, 30, 35),
61
+ "button": (220, 220, 225),
62
+ "button_hover": (200, 200, 210),
63
+ "danger": (200, 80, 80),
64
+ "success": (80, 180, 120),
65
+ }
66
+
67
+
68
+ # ------------------------------------------------------------
69
+ # Button class
70
+ # ------------------------------------------------------------
71
+ class Button:
72
+ def __init__(self, rect, text, callback):
73
+ self.rect = pygame.Rect(rect)
74
+ self.text = text
75
+ self.callback = callback
76
+ self.hovered = False
77
+
78
+ def handle_event(self, event):
79
+ if event.type == pygame.MOUSEMOTION:
80
+ self.hovered = self.rect.collidepoint(event.pos)
81
+ elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
82
+ if self.rect.collidepoint(event.pos):
83
+ self.callback()
84
+
85
+ def draw(self, surface, colors, font):
86
+ bg = colors["button_hover"] if self.hovered else colors["button"]
87
+ pygame.draw.rect(surface, bg, self.rect, border_radius=6)
88
+ pygame.draw.rect(surface, colors["border"], self.rect, width=1, border_radius=6)
89
+ text_surf = font.render(self.text, True, colors["text"])
90
+ text_rect = text_surf.get_rect(center=self.rect.center)
91
+ surface.blit(text_surf, text_rect)
92
+
93
+
94
+ # ------------------------------------------------------------
95
+ # Main application
96
+ # ------------------------------------------------------------
97
+ class VDrontLauncher:
98
+ def __init__(self):
99
+ pygame.init()
100
+ self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
101
+ pygame.display.set_caption("VDrontV3-Launcher")
102
+ self.clock = pygame.time.Clock()
103
+ self.running = True
104
+
105
+ # State
106
+ self.theme = "dark"
107
+ self.colors = get_theme_colors(self.theme)
108
+ self.settings_open = False
109
+ self.qualitative = False
110
+ self.input_text = ""
111
+ self.input_active = True
112
+ self.messages = []
113
+ self.scroll_offset = 0
114
+ self.max_scroll = 0
115
+ self.generating = False
116
+ self.gen_thread = None
117
+ self.gen_done = False
118
+ self.gen_result = None
119
+
120
+ # Generation params (normal mode by default)
121
+ self.params = {
122
+ "temperature": 0.45,
123
+ "max_new_tokens": 256,
124
+ "repetition_penalty": 1.1,
125
+ "top_k": 50,
126
+ "output_version": 0,
127
+ }
128
+
129
+ # Fonts
130
+ self.font = self._get_font(18)
131
+ self.font_small = self._get_font(14)
132
+ self.font_big = self._get_font(22)
133
+
134
+ # Load model
135
+ self._show_loading("Loading model...")
136
+ self.tokenizer, self.model, self.device = self._load_model()
137
+ self._show_loading("Ready")
138
+
139
+ # UI elements
140
+ self.top_buttons = []
141
+ self.send_button = None
142
+ self._create_buttons()
143
+
144
+ # --------------------------------------------------------
145
+ # Fonts
146
+ # --------------------------------------------------------
147
+ @staticmethod
148
+ def _get_font(size, bold=False):
149
+ candidates = ["Arial", "DejaVu Sans", "Segoe UI", "Verdana", "Helvetica"]
150
+ for name in candidates:
151
+ path = pygame.font.match_font(name, bold=bold)
152
+ if path:
153
+ return pygame.font.Font(path, size)
154
+ return pygame.font.Font(None, size)
155
+
156
+ def _show_loading(self, text):
157
+ self.screen.fill(self.colors["background"])
158
+ surf = self.font_big.render(text, True, self.colors["text"])
159
+ rect = surf.get_rect(center=self.screen.get_rect().center)
160
+ self.screen.blit(surf, rect)
161
+ pygame.display.flip()
162
+
163
+ # --------------------------------------------------------
164
+ # Model loading
165
+ # --------------------------------------------------------
166
+ def _load_model(self):
167
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
168
+ tokenizer = GPT2TokenizerFast.from_pretrained(MODEL_DIR)
169
+ vocab_size = len(tokenizer)
170
+
171
+ special_tokens = [USER_TOKEN, ASSISTANT_TOKEN]
172
+ tokenizer.add_special_tokens({"additional_special_tokens": special_tokens})
173
+
174
+ with open(os.path.join(MODEL_DIR, "architecture.json")) as f:
175
+ arch = json.load(f)
176
+
177
+ config = GPT2Config(
178
+ vocab_size=vocab_size,
179
+ n_embd=arch["n_embd"],
180
+ n_head=arch["n_head"],
181
+ n_layer=arch["n_layer"],
182
+ n_positions=arch["n_positions"],
183
+ layer_norm_epsilon=1e-5,
184
+ )
185
+
186
+ model = VDrontModel(
187
+ config=config,
188
+ expert_start=arch["expert_start"],
189
+ expert_end=arch["expert_end"],
190
+ output_index=arch["output_index"],
191
+ num_experts=arch["num_experts"],
192
+ num_output_versions=arch["num_output_versions"],
193
+ )
194
+
195
+ state = load_file(os.path.join(MODEL_DIR, "model.safetensors"))
196
+ model.load_state_dict(state)
197
+ model.to(device)
198
+ model.eval()
199
+
200
+ # Resize embeddings if tokenizer was extended
201
+ if model.embed_tokens.num_embeddings < len(tokenizer):
202
+ old_embed = model.embed_tokens
203
+ new_embed = torch.nn.Embedding(len(tokenizer), old_embed.embedding_dim).to(device)
204
+ new_embed.weight.data[:old_embed.num_embeddings] = old_embed.weight.data.to(device)
205
+ model.embed_tokens = new_embed
206
+
207
+ old_lm_head = model.lm_head
208
+ new_lm_head = torch.nn.Linear(old_lm_head.in_features, len(tokenizer), bias=False).to(device)
209
+ new_lm_head.weight.data[:old_lm_head.out_features] = old_lm_head.weight.data.to(device)
210
+ model.lm_head = new_lm_head
211
+
212
+ model.config.vocab_size = len(tokenizer)
213
+
214
+ return tokenizer, model, device
215
+
216
+ # --------------------------------------------------------
217
+ # UI creation
218
+ # --------------------------------------------------------
219
+ def _create_buttons(self):
220
+ self.theme_button = Button((20, 10, 120, 30), "", self._toggle_theme)
221
+ self.qualitative_button = Button((150, 10, 140, 30), "", self._toggle_qualitative)
222
+ self.settings_button = Button((300, 10, 100, 30), "Settings", self._open_settings)
223
+ self.clear_button = Button((410, 10, 80, 30), "Clear", self._clear_chat)
224
+ self.top_buttons = [
225
+ self.theme_button,
226
+ self.qualitative_button,
227
+ self.settings_button,
228
+ self.clear_button,
229
+ ]
230
+ self.send_button = Button((WINDOW_WIDTH - 120, WINDOW_HEIGHT - 60, 100, 40), "Send", self._send_message)
231
+
232
+ # --------------------------------------------------------
233
+ # Button callbacks
234
+ # --------------------------------------------------------
235
+ def _toggle_theme(self):
236
+ self.theme = "light" if self.theme == "dark" else "dark"
237
+ self.colors = get_theme_colors(self.theme)
238
+
239
+ def _toggle_qualitative(self):
240
+ self.qualitative = not self.qualitative
241
+ if self.qualitative:
242
+ self.params = {
243
+ "temperature": 0.3,
244
+ "max_new_tokens": 512,
245
+ "repetition_penalty": 1.4,
246
+ "top_k": 50,
247
+ "output_version": 1,
248
+ }
249
+ else:
250
+ self.params = {
251
+ "temperature": 0.45,
252
+ "max_new_tokens": 256,
253
+ "repetition_penalty": 1.1,
254
+ "top_k": 50,
255
+ "output_version": 0,
256
+ }
257
+
258
+ def _open_settings(self):
259
+ self.settings_open = True
260
+
261
+ def _clear_chat(self):
262
+ self.messages.clear()
263
+ self.scroll_offset = 0
264
+
265
+ # --------------------------------------------------------
266
+ # Generation (run in separate thread)
267
+ # --------------------------------------------------------
268
+ def _generate_thread(self, prompt):
269
+ try:
270
+ self.model.set_output_version(self.params["output_version"])
271
+ input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.device)
272
+ generated_tokens = []
273
+ eos_id = self.tokenizer.eos_token_id
274
+
275
+ with torch.no_grad():
276
+ for _ in range(self.params["max_new_tokens"]):
277
+ pos = torch.arange(0, input_ids.size(1), device=self.device).unsqueeze(0)
278
+ x = self.model.embed_tokens(input_ids) + self.model.embed_positions(pos)
279
+ router_logits = self.model.router(x.mean(dim=1))
280
+ expert_idx = router_logits.argmax(dim=-1).item()
281
+ self.model.set_expert_version(expert_idx)
282
+
283
+ idx_cond = input_ids[:, -self.model.config.n_positions:]
284
+ logits, _ = self.model(idx_cond)
285
+ logits = logits[:, -1, :] / self.params["temperature"]
286
+
287
+ for token_id in set(input_ids[0].tolist()):
288
+ logits[0, token_id] /= self.params["repetition_penalty"]
289
+
290
+ if self.params["top_k"] is not None and self.params["top_k"] > 0:
291
+ v, _ = torch.topk(logits, min(self.params["top_k"], logits.size(-1)))
292
+ logits[logits < v[:, [-1]]] = -float("Inf")
293
+
294
+ probs = F.softmax(logits, dim=-1)
295
+ idx_next = torch.multinomial(probs, num_samples=1)
296
+ next_token = idx_next.item()
297
+
298
+ if next_token == eos_id:
299
+ break
300
+
301
+ generated_tokens.append(next_token)
302
+ input_ids = torch.cat((input_ids, idx_next), dim=1)
303
+
304
+ full_text = self.tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
305
+ self.gen_result = full_text
306
+ except Exception as e:
307
+ self.gen_result = f"[Error] {e}"
308
+ finally:
309
+ self.gen_done = True
310
+
311
+ def _send_message(self):
312
+ text = self.input_text.strip()
313
+ if not text or self.generating:
314
+ return
315
+
316
+ self.messages.append({"role": "user", "text": text})
317
+ self.input_text = ""
318
+ self.scroll_offset = 0
319
+
320
+ prompt = f"{USER_TOKEN}{text}{ASSISTANT_TOKEN}"
321
+ self.generating = True
322
+ self.gen_done = False
323
+ self.gen_result = None
324
+ self.gen_thread = threading.Thread(target=self._generate_thread, args=(prompt,), daemon=True)
325
+ self.gen_thread.start()
326
+
327
+ # --------------------------------------------------------
328
+ # Event handling
329
+ # --------------------------------------------------------
330
+ def _handle_events(self):
331
+ for event in pygame.event.get():
332
+ if event.type == pygame.QUIT:
333
+ self.running = False
334
+
335
+ if self.settings_open:
336
+ self._handle_settings_event(event)
337
+ else:
338
+ self._handle_main_event(event)
339
+
340
+ def _handle_main_event(self, event):
341
+ # Buttons
342
+ for btn in self.top_buttons:
343
+ btn.handle_event(event)
344
+ self.send_button.handle_event(event)
345
+
346
+ # Mouse wheel scroll
347
+ if event.type == pygame.MOUSEWHEEL:
348
+ self.scroll_offset = max(0, min(self.max_scroll, self.scroll_offset - event.y * 30))
349
+
350
+ # Mouse click for input activation
351
+ if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
352
+ input_rect = pygame.Rect(20, WINDOW_HEIGHT - 60, WINDOW_WIDTH - 140, 40)
353
+ self.input_active = input_rect.collidepoint(event.pos)
354
+
355
+ # Keyboard input
356
+ if event.type == pygame.KEYDOWN:
357
+ if event.key == pygame.K_RETURN:
358
+ self._send_message()
359
+ elif event.key == pygame.K_BACKSPACE:
360
+ self.input_text = self.input_text[:-1]
361
+ elif event.unicode and event.unicode.isprintable():
362
+ self.input_text += event.unicode
363
+
364
+ def _handle_settings_event(self, event):
365
+ if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
366
+ # Close button / click outside
367
+ panel_rect = pygame.Rect(
368
+ (WINDOW_WIDTH - 500) // 2,
369
+ (WINDOW_HEIGHT - 380) // 2,
370
+ 500,
371
+ 380,
372
+ )
373
+ close_rect = pygame.Rect(panel_rect.right - 35, panel_rect.y + 10, 25, 25)
374
+ if close_rect.collidepoint(event.pos) or not panel_rect.collidepoint(event.pos):
375
+ self.settings_open = False
376
+ return
377
+
378
+ # Check row controls
379
+ for key, action, rect in self.settings_controls:
380
+ if rect.collidepoint(event.pos):
381
+ self._adjust_param(key, action)
382
+ break
383
+
384
+ # --------------------------------------------------------
385
+ # Settings
386
+ # --------------------------------------------------------
387
+ def _adjust_param(self, key, action):
388
+ row = next((r for r in self.settings_rows if r["key"] == key), None)
389
+ if not row:
390
+ return
391
+
392
+ if key == "output_version":
393
+ self.params[key] = 0 if self.params[key] == 1 else 1
394
+ else:
395
+ step = row["step"]
396
+ value = self.params[key]
397
+ new_value = value + step if action == "plus" else value - step
398
+ new_value = max(row["min"], min(row["max"], new_value))
399
+
400
+ if isinstance(step, int):
401
+ new_value = int(round(new_value))
402
+ else:
403
+ new_value = round(new_value, 2)
404
+
405
+ self.params[key] = new_value
406
+
407
+ # Manual adjustment means qualitative preset is no longer active
408
+ self.qualitative = False
409
+
410
+ # --------------------------------------------------------
411
+ # Update
412
+ # --------------------------------------------------------
413
+ def _update(self):
414
+ # Update button labels
415
+ self.theme_button.text = f"Theme: {'Dark' if self.theme == 'dark' else 'Light'}"
416
+ self.qualitative_button.text = f"Qualitative: {'ON' if self.qualitative else 'OFF'}"
417
+
418
+ # Check generation completion
419
+ if self.generating and self.gen_done:
420
+ result = self.gen_result if self.gen_result is not None else "[No response]"
421
+ self.messages.append({"role": "ai", "text": result})
422
+ self.generating = False
423
+ self.gen_done = False
424
+ self.gen_result = None
425
+ self.gen_thread = None
426
+ self.scroll_offset = 0
427
+
428
+ # --------------------------------------------------------
429
+ # Drawing
430
+ # --------------------------------------------------------
431
+ def _draw(self):
432
+ self.screen.fill(self.colors["background"])
433
+ self._draw_top_bar()
434
+ self._draw_chat()
435
+ self._draw_input()
436
+ if self.generating:
437
+ self._draw_typing_indicator()
438
+ if self.settings_open:
439
+ self._draw_settings()
440
+ pygame.display.flip()
441
+
442
+ def _draw_top_bar(self):
443
+ for btn in self.top_buttons:
444
+ btn.draw(self.screen, self.colors, self.font_small)
445
+
446
+ def _draw_input(self):
447
+ input_rect = pygame.Rect(20, WINDOW_HEIGHT - 60, WINDOW_WIDTH - 140, 40)
448
+ pygame.draw.rect(self.screen, self.colors["input_bg"], input_rect, border_radius=6)
449
+ pygame.draw.rect(self.screen, self.colors["border"], input_rect, width=1, border_radius=6)
450
+
451
+ # Render input text (clipped)
452
+ text_surf = self.font.render(self.input_text, True, self.colors["text"])
453
+ clip_rect = input_rect.inflate(-10, -10)
454
+ self.screen.set_clip(clip_rect)
455
+ self.screen.blit(text_surf, (input_rect.x + 10, input_rect.y + 8))
456
+ self.screen.set_clip(None)
457
+
458
+ # Blinking cursor
459
+ if self.input_active and pygame.time.get_ticks() % 1000 < 500:
460
+ cursor_x = input_rect.x + 10 + text_surf.get_width() + 2
461
+ if cursor_x < input_rect.right - 10:
462
+ pygame.draw.line(
463
+ self.screen,
464
+ self.colors["text"],
465
+ (cursor_x, input_rect.y + 8),
466
+ (cursor_x, input_rect.y + 32),
467
+ 2,
468
+ )
469
+
470
+ self.send_button.draw(self.screen, self.colors, self.font)
471
+
472
+ def _draw_typing_indicator(self):
473
+ text = "AI is typing..."
474
+ surf = self.font_small.render(text, True, self.colors["text_secondary"])
475
+ rect = surf.get_rect(topleft=(20, WINDOW_HEIGHT - 75))
476
+ self.screen.blit(surf, rect)
477
+
478
+ def _draw_chat(self):
479
+ chat_rect = pygame.Rect(20, 50, WINDOW_WIDTH - 40, WINDOW_HEIGHT - 130)
480
+ pygame.draw.rect(self.screen, self.colors["surface"], chat_rect, border_radius=8)
481
+
482
+ # Calculate total content height for scrollbar
483
+ total_height = 0
484
+ wrapped_cache = []
485
+ for msg in self.messages:
486
+ bubble_width = chat_rect.width - 40
487
+ wrapped = self._wrap_text(msg["text"], self.font, bubble_width - 20)
488
+ line_height = self.font.get_linesize()
489
+ bubble_height = line_height * len(wrapped) + 20
490
+ total_height += bubble_height + 10 # spacing
491
+ wrapped_cache.append((msg, wrapped, bubble_height))
492
+ self.max_scroll = max(0, total_height - chat_rect.height)
493
+ self.scroll_offset = max(0, min(self.scroll_offset, self.max_scroll))
494
+
495
+ self.screen.set_clip(chat_rect)
496
+ y = chat_rect.bottom - 10 + self.scroll_offset
497
+
498
+ for msg, wrapped, bubble_height in reversed(wrapped_cache):
499
+ bubble_rect = pygame.Rect(chat_rect.x + 10, y - bubble_height, chat_rect.width - 40, bubble_height)
500
+
501
+ if bubble_rect.bottom < chat_rect.top:
502
+ break
503
+
504
+ if bubble_rect.top <= chat_rect.bottom:
505
+ if msg["role"] == "user":
506
+ bubble_rect.right = chat_rect.right - 10
507
+ bg = self.colors["user_bubble"]
508
+ fg = self.colors["user_text"]
509
+ else:
510
+ bubble_rect.left = chat_rect.x + 10
511
+ bg = self.colors["ai_bubble"]
512
+ fg = self.colors["ai_text"]
513
+
514
+ pygame.draw.rect(self.screen, bg, bubble_rect, border_radius=10)
515
+
516
+ line_height = self.font.get_linesize()
517
+ text_y = bubble_rect.y + 10
518
+ for line in wrapped:
519
+ line_surf = self.font.render(line, True, fg)
520
+ if msg["role"] == "user":
521
+ self.screen.blit(line_surf, (bubble_rect.right - 15 - line_surf.get_width(), text_y))
522
+ else:
523
+ self.screen.blit(line_surf, (bubble_rect.x + 15, text_y))
524
+ text_y += line_height
525
+
526
+ y = bubble_rect.y - 10
527
+
528
+ self.screen.set_clip(None)
529
+
530
+ # Scrollbar
531
+ if total_height > chat_rect.height:
532
+ scrollbar_height = max(30, int(chat_rect.height * (chat_rect.height / total_height)))
533
+ scrollbar_y = chat_rect.y + int((chat_rect.height - scrollbar_height) * (self.scroll_offset / self.max_scroll)) if self.max_scroll > 0 else chat_rect.y
534
+ scrollbar_rect = pygame.Rect(chat_rect.right - 6, scrollbar_y, 4, scrollbar_height)
535
+ pygame.draw.rect(self.screen, self.colors["border"], scrollbar_rect, border_radius=2)
536
+
537
+ def _draw_settings(self):
538
+ panel_width = 500
539
+ panel_height = 380
540
+ panel_x = (WINDOW_WIDTH - panel_width) // 2
541
+ panel_y = (WINDOW_HEIGHT - panel_height) // 2
542
+ panel_rect = pygame.Rect(panel_x, panel_y, panel_width, panel_height)
543
+
544
+ # Overlay
545
+ overlay = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA)
546
+ overlay.fill((0, 0, 0, 128))
547
+ self.screen.blit(overlay, (0, 0))
548
+
549
+ pygame.draw.rect(self.screen, self.colors["surface"], panel_rect, border_radius=12)
550
+ pygame.draw.rect(self.screen, self.colors["border"], panel_rect, width=2, border_radius=12)
551
+
552
+ # Title
553
+ title_surf = self.font_big.render("Settings", True, self.colors["text"])
554
+ self.screen.blit(title_surf, (panel_x + 20, panel_y + 15))
555
+
556
+ # Close button
557
+ close_rect = pygame.Rect(panel_rect.right - 35, panel_y + 10, 25, 25)
558
+ pygame.draw.rect(self.screen, self.colors["button"], close_rect, border_radius=6)
559
+ pygame.draw.rect(self.screen, self.colors["border"], close_rect, width=1, border_radius=6)
560
+ close_text = self.font_small.render("X", True, self.colors["text"])
561
+ self.screen.blit(close_text, close_text.get_rect(center=close_rect.center))
562
+
563
+ # Settings rows
564
+ self.settings_rows = [
565
+ {"key": "temperature", "label": "Temperature", "min": 0.1, "max": 2.0, "step": 0.05},
566
+ {"key": "max_new_tokens", "label": "Max Tokens", "min": 32, "max": 1024, "step": 32},
567
+ {"key": "repetition_penalty", "label": "Repetition Penalty", "min": 0.8, "max": 2.0, "step": 0.1},
568
+ {"key": "top_k", "label": "Top K", "min": 0, "max": 100, "step": 5},
569
+ {"key": "output_version", "label": "Output Version", "min": 0, "max": 1, "step": 1},
570
+ ]
571
+ self.settings_controls = []
572
+
573
+ for i, row in enumerate(self.settings_rows):
574
+ y = panel_y + 70 + i * 55
575
+
576
+ # Label
577
+ label_surf = self.font.render(row["label"], True, self.colors["text"])
578
+ self.screen.blit(label_surf, (panel_x + 25, y))
579
+
580
+ # Minus button
581
+ minus_rect = pygame.Rect(panel_x + 310, y, 30, 30)
582
+ pygame.draw.rect(self.screen, self.colors["button"], minus_rect, border_radius=6)
583
+ pygame.draw.rect(self.screen, self.colors["border"], minus_rect, width=1, border_radius=6)
584
+ minus_text = self.font.render("-", True, self.colors["text"])
585
+ self.screen.blit(minus_text, minus_text.get_rect(center=minus_rect.center))
586
+ self.settings_controls.append((row["key"], "minus", minus_rect))
587
+
588
+ # Value
589
+ value_surf = self.font.render(str(self.params[row["key"]]), True, self.colors["text"])
590
+ value_rect = value_surf.get_rect(center=(panel_x + 370, y + 15))
591
+ self.screen.blit(value_surf, value_rect)
592
+
593
+ # Plus button
594
+ plus_rect = pygame.Rect(panel_x + 410, y, 30, 30)
595
+ pygame.draw.rect(self.screen, self.colors["button"], plus_rect, border_radius=6)
596
+ pygame.draw.rect(self.screen, self.colors["border"], plus_rect, width=1, border_radius=6)
597
+ plus_text = self.font.render("+", True, self.colors["text"])
598
+ self.screen.blit(plus_text, plus_text.get_rect(center=plus_rect.center))
599
+ self.settings_controls.append((row["key"], "plus", plus_rect))
600
+
601
+ # --------------------------------------------------------
602
+ # Text wrapping
603
+ # --------------------------------------------------------
604
+ def _wrap_text(self, text, font, max_width):
605
+ words = text.split(" ")
606
+ lines = []
607
+ current = ""
608
+
609
+ for word in words:
610
+ test = word if not current else current + " " + word
611
+ if font.size(test)[0] <= max_width:
612
+ current = test
613
+ else:
614
+ if current:
615
+ lines.append(current)
616
+ current = word
617
+ else:
618
+ # Very long word, split by characters
619
+ while font.size(word)[0] > max_width:
620
+ split_idx = len(word)
621
+ for i in range(1, len(word)):
622
+ if font.size(word[:i])[0] > max_width:
623
+ split_idx = i - 1
624
+ break
625
+ if split_idx == len(word):
626
+ break
627
+ lines.append(word[:split_idx])
628
+ word = word[split_idx:]
629
+ current = word
630
+ if current:
631
+ lines.append(current)
632
+ return lines
633
+
634
+ # --------------------------------------------------------
635
+ # Main loop
636
+ # --------------------------------------------------------
637
+ def run(self):
638
+ while self.running:
639
+ self.clock.tick(FPS)
640
+ self._handle_events()
641
+ self._update()
642
+ self._draw()
643
+
644
+ pygame.quit()
645
+
646
+
647
+ if __name__ == "__main__":
648
+ app = VDrontLauncher()
649
+ app.run()
added_tokens.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "<|assistant|>": 50258,
3
+ "<|user|>": 50257
4
+ }
architecture.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"expert_start": 0, "expert_end": 3, "output_index": 8, "num_experts": 3, "num_output_versions": 2, "vocab_size": 50259, "n_embd": 768, "n_head": 12, "n_layer": 9, "n_positions": 1024}
config.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"vocab_size": 50259, "n_positions": 1024, "n_embd": 768, "n_layer": 9, "n_head": 12, "n_inner": null, "activation_function": "gelu_new", "resid_pdrop": 0.1, "embd_pdrop": 0.1, "attn_pdrop": 0.1, "layer_norm_epsilon": 1e-05, "initializer_range": 0.02, "summary_type": "cls_index", "summary_use_proj": true, "summary_activation": null, "summary_first_dropout": 0.1, "summary_proj_to_labels": true, "scale_attn_weights": true, "use_cache": false, "scale_attn_by_inverse_layer_idx": false, "reorder_and_upcast_attn": false, "bos_token_id": 50256, "eos_token_id": 50256, "return_dict": true, "output_hidden_states": false, "output_attentions": false, "torchscript": false, "torch_dtype": "float32", "use_bfloat16": false, "tf_legacy_loss": false, "pruned_heads": {}, "tie_word_embeddings": true, "chunk_size_feed_forward": 0, "is_encoder_decoder": false, "is_decoder": false, "cross_attention_hidden_size": null, "add_cross_attention": false, "tie_encoder_decoder": false, "max_length": 20, "min_length": 0, "do_sample": false, "early_stopping": false, "num_beams": 1, "num_beam_groups": 1, "diversity_penalty": 0.0, "temperature": 1.0, "top_k": 50, "top_p": 1.0, "typical_p": 1.0, "repetition_penalty": 1.0, "length_penalty": 1.0, "no_repeat_ngram_size": 0, "encoder_no_repeat_ngram_size": 0, "bad_words_ids": null, "num_return_sequences": 1, "output_scores": false, "return_dict_in_generate": false, "forced_bos_token_id": null, "forced_eos_token_id": null, "remove_invalid_values": false, "exponential_decay_length_penalty": null, "suppress_tokens": null, "begin_suppress_tokens": null, "architectures": ["GPT2LMHeadModel"], "finetuning_task": null, "id2label": {"0": "LABEL_0", "1": "LABEL_1"}, "label2id": {"LABEL_0": 0, "LABEL_1": 1}, "tokenizer_class": null, "prefix": null, "pad_token_id": null, "sep_token_id": null, "decoder_start_token_id": null, "task_specific_params": null, "problem_type": null, "_name_or_path": "Base", "_attn_implementation_autoset": true, "transformers_version": "4.46.3", "model_type": "gpt2", "n_ctx": 1024}
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from transformers import GPT2Config
5
+ from transformers.models.gpt2.modeling_gpt2 import GPT2Block
6
+ from typing import List
7
+ import copy
8
+
9
+ class ExpertBlock(nn.Module):
10
+ def __init__(self, layers: List[nn.Module], num_versions: int, config=None):
11
+ super().__init__()
12
+ self.num_versions = num_versions
13
+ self.config = config
14
+ self.versions = nn.ModuleList([
15
+ nn.ModuleList([copy.deepcopy(layer) for layer in layers])
16
+ for _ in range(num_versions)
17
+ ])
18
+ self.active_version = 0
19
+
20
+ def set_version(self, idx):
21
+ self.active_version = idx
22
+
23
+ def forward(self, x, **kwargs):
24
+ for layer in self.versions[self.active_version]:
25
+ out = layer(x, **kwargs)
26
+ if isinstance(out, tuple):
27
+ x = out[0]
28
+ else:
29
+ x = out
30
+ return x
31
+
32
+ class VDrontModel(nn.Module):
33
+ def __init__(self, config, expert_start, expert_end, output_index, num_experts, num_output_versions):
34
+ super().__init__()
35
+ self.config = config
36
+ self.num_experts = num_experts
37
+ self.num_output_versions = num_output_versions
38
+ self.expert_start = expert_start
39
+ self.expert_end = expert_end
40
+ self.output_index = output_index
41
+
42
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.n_embd)
43
+ self.embed_positions = nn.Embedding(config.n_positions, config.n_embd)
44
+
45
+ all_layers = [GPT2Block(config, layer_idx=i) for i in range(config.n_layer)]
46
+ expert_layers = all_layers[expert_start:expert_end+1]
47
+ base_layers = all_layers[expert_end+1:output_index]
48
+ output_layer = all_layers[output_index]
49
+
50
+ self.expert_block = ExpertBlock(expert_layers, num_experts, config=config)
51
+ self.base_blocks = nn.ModuleList(base_layers)
52
+ self.output_block = ExpertBlock([output_layer], num_output_versions, config=config)
53
+
54
+ self.ln_f = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
55
+ self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)
56
+ self.router = nn.Linear(config.n_embd, num_experts, bias=False)
57
+
58
+ self.apply(self._init_weights)
59
+
60
+ def _init_weights(self, module):
61
+ if isinstance(module, (nn.Linear, nn.Embedding)):
62
+ module.weight.data.normal_(mean=0.0, std=0.02)
63
+ if isinstance(module, nn.Linear) and module.bias is not None:
64
+ module.bias.data.zero_()
65
+
66
+ def set_expert_version(self, idx):
67
+ self.expert_block.set_version(idx)
68
+
69
+ def set_output_version(self, idx):
70
+ self.output_block.set_version(idx)
71
+
72
+ def forward(self, input_ids, labels=None, return_router_logits=False):
73
+ pos = torch.arange(0, input_ids.size(1), device=input_ids.device).unsqueeze(0)
74
+ x = self.embed_tokens(input_ids) + self.embed_positions(pos)
75
+
76
+ router_logits = self.router(x.mean(dim=1)) if return_router_logits else None
77
+
78
+ x = self.expert_block(x)
79
+ for block in self.base_blocks:
80
+ out = block(x)
81
+ x = out[0] if isinstance(out, tuple) else out
82
+ x = self.output_block(x)
83
+ x = self.ln_f(x)
84
+ logits = self.lm_head(x)
85
+
86
+ loss = None
87
+ if labels is not None:
88
+ # Защита: всё, что вне [0, vocab_size), заменяем на -100 (игнорируем)
89
+ labels = torch.where(
90
+ (labels >= 0) & (labels < self.config.vocab_size),
91
+ labels,
92
+ -100
93
+ )
94
+ loss = F.cross_entropy(
95
+ logits.reshape(-1, logits.size(-1)),
96
+ labels.reshape(-1),
97
+ ignore_index=-100 # ВАЖНО: именно -100, а не -1
98
+ )
99
+
100
+ if return_router_logits:
101
+ return logits, loss, router_logits
102
+ return logits, loss
103
+
104
+ @torch.no_grad()
105
+ def generate(self, input_ids, max_new_tokens, temperature=1.0, top_k=None, dynamic_expert=True):
106
+ self.eval()
107
+ for _ in range(max_new_tokens):
108
+ if dynamic_expert:
109
+ pos = torch.arange(0, input_ids.size(1), device=input_ids.device).unsqueeze(0)
110
+ x = self.embed_tokens(input_ids) + self.embed_positions(pos)
111
+ router_logits = self.router(x.mean(dim=1))
112
+ expert_idx = router_logits.argmax(dim=-1).item()
113
+ self.set_expert_version(expert_idx)
114
+
115
+ idx_cond = input_ids[:, -self.config.n_positions:]
116
+ logits, _ = self(idx_cond)
117
+ logits = logits[:, -1, :] / temperature
118
+ if top_k is not None:
119
+ v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
120
+ logits[logits < v[:, [-1]]] = -float('Inf')
121
+ probs = F.softmax(logits, dim=-1)
122
+ idx_next = torch.multinomial(probs, num_samples=1)
123
+ input_ids = torch.cat((input_ids, idx_next), dim=1)
124
+ return input_ids
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37a135d8409f26cd4804bbb49a65dd0feba32814751ef36c2f935ad0b2ff6835
3
+ size 822303144
special_tokens_map.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ {
4
+ "content": "<|user|>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false
9
+ },
10
+ {
11
+ "content": "<|assistant|>",
12
+ "lstrip": false,
13
+ "normalized": false,
14
+ "rstrip": false,
15
+ "single_word": false
16
+ },
17
+ {
18
+ "content": "<|endoftext|>",
19
+ "lstrip": false,
20
+ "normalized": false,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ }
24
+ ],
25
+ "bos_token": {
26
+ "content": "<|endoftext|>",
27
+ "lstrip": false,
28
+ "normalized": true,
29
+ "rstrip": false,
30
+ "single_word": false
31
+ },
32
+ "eos_token": {
33
+ "content": "<|endoftext|>",
34
+ "lstrip": false,
35
+ "normalized": true,
36
+ "rstrip": false,
37
+ "single_word": false
38
+ },
39
+ "pad_token": {
40
+ "content": "<|endoftext|>",
41
+ "lstrip": false,
42
+ "normalized": true,
43
+ "rstrip": false,
44
+ "single_word": false
45
+ },
46
+ "unk_token": {
47
+ "content": "<|endoftext|>",
48
+ "lstrip": false,
49
+ "normalized": true,
50
+ "rstrip": false,
51
+ "single_word": false
52
+ }
53
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "50256": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "50257": {
13
+ "content": "<|user|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "50258": {
21
+ "content": "<|assistant|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ }
28
+ },
29
+ "additional_special_tokens": [
30
+ "<|user|>",
31
+ "<|assistant|>",
32
+ "<|endoftext|>"
33
+ ],
34
+ "bos_token": "<|endoftext|>",
35
+ "clean_up_tokenization_spaces": false,
36
+ "eos_token": "<|endoftext|>",
37
+ "model_max_length": 1024,
38
+ "pad_token": "<|endoftext|>",
39
+ "tokenizer_class": "GPT2Tokenizer",
40
+ "unk_token": "<|endoftext|>"
41
+ }
use.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # use.py
2
+ import os
3
+ import json
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from transformers import GPT2TokenizerFast, GPT2Config
7
+ from safetensors.torch import load_file
8
+ from model import VDrontModel
9
+
10
+ CONFIG = {
11
+ "model_dir": "./VDrontV3-Mini",
12
+ "temperature": 0.4,
13
+ "top_k": 50,
14
+ "max_new_tokens": 200,
15
+ "repetition_penalty": 1.2,
16
+ "user_token": "<|user|>",
17
+ "assistant_token": "<|assistant|>",
18
+ }
19
+
20
+ def format_prompt(user_input):
21
+ return f"{CONFIG['user_token']}{user_input}{CONFIG['assistant_token']}"
22
+
23
+ def main():
24
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
25
+ tokenizer = GPT2TokenizerFast.from_pretrained(CONFIG['model_dir'])
26
+ vocab_size = len(tokenizer)
27
+
28
+ special_tokens = [CONFIG['user_token'], CONFIG['assistant_token']]
29
+ tokenizer.add_special_tokens({'additional_special_tokens': special_tokens})
30
+
31
+ with open(os.path.join(CONFIG['model_dir'], 'architecture.json')) as f:
32
+ arch = json.load(f)
33
+
34
+ config = GPT2Config(
35
+ vocab_size=vocab_size,
36
+ n_embd=arch['n_embd'],
37
+ n_head=arch['n_head'],
38
+ n_layer=arch['n_layer'],
39
+ n_positions=arch['n_positions'],
40
+ layer_norm_epsilon=1e-5,
41
+ )
42
+
43
+ model = VDrontModel(
44
+ config=config,
45
+ expert_start=arch['expert_start'],
46
+ expert_end=arch['expert_end'],
47
+ output_index=arch['output_index'],
48
+ num_experts=arch['num_experts'],
49
+ num_output_versions=arch['num_output_versions'],
50
+ )
51
+ state = load_file(os.path.join(CONFIG['model_dir'], 'model.safetensors'))
52
+ model.load_state_dict(state)
53
+ model.to(device)
54
+ model.eval()
55
+
56
+ if model.embed_tokens.num_embeddings < len(tokenizer):
57
+ old_embed = model.embed_tokens
58
+ new_embed = torch.nn.Embedding(len(tokenizer), old_embed.embedding_dim).to(device)
59
+ new_embed.weight.data[:old_embed.num_embeddings] = old_embed.weight.data.to(device)
60
+ model.embed_tokens = new_embed
61
+
62
+ old_lm_head = model.lm_head
63
+ new_lm_head = torch.nn.Linear(old_lm_head.in_features, len(tokenizer), bias=False).to(device)
64
+ new_lm_head.weight.data[:old_lm_head.out_features] = old_lm_head.weight.data.to(device)
65
+ model.lm_head = new_lm_head
66
+
67
+ model.config.vocab_size = len(tokenizer)
68
+
69
+ while True:
70
+ try:
71
+ output_ver = int(input("Mode (0 - base (bad, little answer), 1 - qualitative (normal, medium answer): "))
72
+ if output_ver in [0, 1]:
73
+ model.set_output_version(output_ver)
74
+ break
75
+ except ValueError:
76
+ pass
77
+
78
+ print("Chat is ready. Type 'exit' to quit.")
79
+
80
+ while True:
81
+ user_input = input("You: ")
82
+ if user_input.lower() in ['exit', 'quit']:
83
+ break
84
+
85
+ prompt = format_prompt(user_input)
86
+ input_ids = tokenizer.encode(prompt, return_tensors='pt').to(device)
87
+ generated_tokens = []
88
+ eos_id = tokenizer.eos_token_id
89
+
90
+ with torch.no_grad():
91
+ for _ in range(CONFIG['max_new_tokens']):
92
+ pos = torch.arange(0, input_ids.size(1), device=device).unsqueeze(0)
93
+ x = model.embed_tokens(input_ids) + model.embed_positions(pos)
94
+ router_logits = model.router(x.mean(dim=1))
95
+ expert_idx = router_logits.argmax(dim=-1).item()
96
+ model.set_expert_version(expert_idx)
97
+
98
+ idx_cond = input_ids[:, -model.config.n_positions:]
99
+ logits, _ = model(idx_cond)
100
+ logits = logits[:, -1, :] / CONFIG['temperature']
101
+
102
+ for token_id in set(input_ids[0].tolist()):
103
+ logits[0, token_id] /= CONFIG['repetition_penalty']
104
+
105
+ if CONFIG['top_k'] is not None:
106
+ v, _ = torch.topk(logits, min(CONFIG['top_k'], logits.size(-1)))
107
+ logits[logits < v[:, [-1]]] = -float('Inf')
108
+
109
+ probs = F.softmax(logits, dim=-1)
110
+ idx_next = torch.multinomial(probs, num_samples=1)
111
+ next_token = idx_next.item()
112
+
113
+ if next_token == eos_id:
114
+ break
115
+
116
+ generated_tokens.append(next_token)
117
+ input_ids = torch.cat((input_ids, idx_next), dim=1)
118
+
119
+ full_text = tokenizer.decode(generated_tokens, skip_special_tokens=True)
120
+ print(f"AI: {full_text}")
121
+
122
+ if __name__ == '__main__':
123
+ main()
vocab.json ADDED
The diff for this file is too large to render. See raw diff