vedaco commited on
Commit
d7c8b67
·
verified ·
1 Parent(s): cc1f992

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1092 -0
app.py ADDED
@@ -0,0 +1,1092 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Visible LLM - A Language Model built with TensorFlow
3
+ Trained on veda.txt
4
+ """
5
+
6
+ import os
7
+ import json
8
+ import numpy as np
9
+ import tensorflow as tf
10
+ from tensorflow import keras
11
+ from tensorflow.keras import layers
12
+ from flask import Flask, request, jsonify, render_template_string
13
+ import re
14
+ import pickle
15
+ from datetime import datetime
16
+
17
+ # ============================================================
18
+ # CONFIGURATION
19
+ # ============================================================
20
+
21
+ class VisibleConfig:
22
+ """Configuration for Visible LLM"""
23
+ MODEL_NAME = "Visible"
24
+ VERSION = "1.0.0"
25
+
26
+ # Model Architecture
27
+ VOCAB_SIZE = 10000
28
+ EMBEDDING_DIM = 256
29
+ NUM_HEADS = 8
30
+ NUM_LAYERS = 6
31
+ FF_DIM = 512
32
+ MAX_SEQ_LENGTH = 128
33
+ DROPOUT_RATE = 0.1
34
+
35
+ # Training
36
+ BATCH_SIZE = 32
37
+ EPOCHS = 50
38
+ LEARNING_RATE = 0.0001
39
+ WARMUP_STEPS = 4000
40
+
41
+ # Paths
42
+ DATA_FILE = "veda.txt"
43
+ MODEL_DIR = "models"
44
+ MODEL_PATH = "models/visible_model"
45
+ TOKENIZER_PATH = "models/visible_tokenizer.pkl"
46
+ CONFIG_PATH = "models/visible_config.json"
47
+
48
+
49
+ # ============================================================
50
+ # CUSTOM TOKENIZER
51
+ # ============================================================
52
+
53
+ class VisibleTokenizer:
54
+ """Custom tokenizer for Visible LLM"""
55
+
56
+ def __init__(self, vocab_size=10000):
57
+ self.vocab_size = vocab_size
58
+ self.word_to_idx = {}
59
+ self.idx_to_word = {}
60
+ self.vocab = []
61
+
62
+ # Special tokens
63
+ self.pad_token = "<PAD>"
64
+ self.unk_token = "<UNK>"
65
+ self.start_token = "<START>"
66
+ self.end_token = "<END>"
67
+
68
+ self.pad_token_id = 0
69
+ self.unk_token_id = 1
70
+ self.start_token_id = 2
71
+ self.end_token_id = 3
72
+
73
+ def _preprocess_text(self, text):
74
+ """Clean and preprocess text"""
75
+ text = text.lower()
76
+ text = re.sub(r'[^\w\s\.\,\!\?\;\:\'\"\-]', '', text)
77
+ text = re.sub(r'\s+', ' ', text)
78
+ return text.strip()
79
+
80
+ def _tokenize(self, text):
81
+ """Split text into tokens"""
82
+ text = self._preprocess_text(text)
83
+ # Simple word-level tokenization with punctuation handling
84
+ tokens = re.findall(r'\w+|[^\w\s]', text)
85
+ return tokens
86
+
87
+ def fit(self, texts):
88
+ """Build vocabulary from texts"""
89
+ print("Building vocabulary...")
90
+ word_counts = {}
91
+
92
+ for text in texts:
93
+ tokens = self._tokenize(text)
94
+ for token in tokens:
95
+ word_counts[token] = word_counts.get(token, 0) + 1
96
+
97
+ # Sort by frequency
98
+ sorted_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)
99
+
100
+ # Build vocabulary with special tokens
101
+ self.vocab = [self.pad_token, self.unk_token, self.start_token, self.end_token]
102
+ self.vocab.extend([word for word, _ in sorted_words[:self.vocab_size - 4]])
103
+
104
+ self.word_to_idx = {word: idx for idx, word in enumerate(self.vocab)}
105
+ self.idx_to_word = {idx: word for idx, word in enumerate(self.vocab)}
106
+
107
+ print(f"Vocabulary size: {len(self.vocab)}")
108
+ return self
109
+
110
+ def encode(self, text, max_length=None, add_special_tokens=True):
111
+ """Encode text to token ids"""
112
+ tokens = self._tokenize(text)
113
+
114
+ if add_special_tokens:
115
+ tokens = [self.start_token] + tokens + [self.end_token]
116
+
117
+ token_ids = [self.word_to_idx.get(token, self.unk_token_id) for token in tokens]
118
+
119
+ if max_length:
120
+ if len(token_ids) > max_length:
121
+ token_ids = token_ids[:max_length]
122
+ else:
123
+ token_ids.extend([self.pad_token_id] * (max_length - len(token_ids)))
124
+
125
+ return token_ids
126
+
127
+ def decode(self, token_ids, skip_special_tokens=True):
128
+ """Decode token ids to text"""
129
+ special_ids = {self.pad_token_id, self.start_token_id, self.end_token_id}
130
+
131
+ tokens = []
132
+ for idx in token_ids:
133
+ if skip_special_tokens and idx in special_ids:
134
+ continue
135
+ if idx == self.unk_token_id and skip_special_tokens:
136
+ tokens.append("<?>")
137
+ else:
138
+ tokens.append(self.idx_to_word.get(idx, self.unk_token))
139
+
140
+ # Join tokens properly
141
+ text = ' '.join(tokens)
142
+ # Fix punctuation spacing
143
+ text = re.sub(r'\s+([.,!?;:])', r'\1', text)
144
+ return text
145
+
146
+ def save(self, path):
147
+ """Save tokenizer to file"""
148
+ with open(path, 'wb') as f:
149
+ pickle.dump({
150
+ 'vocab': self.vocab,
151
+ 'vocab_size': self.vocab_size
152
+ }, f)
153
+ print(f"Tokenizer saved to {path}")
154
+
155
+ def load(self, path):
156
+ """Load tokenizer from file"""
157
+ with open(path, 'rb') as f:
158
+ data = pickle.load(f)
159
+ self.vocab = data['vocab']
160
+ self.vocab_size = data['vocab_size']
161
+ self.word_to_idx = {word: idx for idx, word in enumerate(self.vocab)}
162
+ self.idx_to_word = {idx: word for idx, word in enumerate(self.vocab)}
163
+ print(f"Tokenizer loaded from {path}")
164
+ return self
165
+
166
+ def __len__(self):
167
+ return len(self.vocab)
168
+
169
+
170
+ # ============================================================
171
+ # TRANSFORMER COMPONENTS
172
+ # ============================================================
173
+
174
+ class PositionalEncoding(layers.Layer):
175
+ """Positional encoding layer"""
176
+
177
+ def __init__(self, max_seq_length, embed_dim, **kwargs):
178
+ super().__init__(**kwargs)
179
+ self.max_seq_length = max_seq_length
180
+ self.embed_dim = embed_dim
181
+
182
+ # Create positional encoding matrix
183
+ position = np.arange(max_seq_length)[:, np.newaxis]
184
+ div_term = np.exp(np.arange(0, embed_dim, 2) * -(np.log(10000.0) / embed_dim))
185
+
186
+ pe = np.zeros((max_seq_length, embed_dim))
187
+ pe[:, 0::2] = np.sin(position * div_term)
188
+ pe[:, 1::2] = np.cos(position * div_term)
189
+
190
+ self.positional_encoding = tf.constant(pe, dtype=tf.float32)
191
+
192
+ def call(self, x):
193
+ seq_length = tf.shape(x)[1]
194
+ return x + self.positional_encoding[:seq_length, :]
195
+
196
+ def get_config(self):
197
+ config = super().get_config()
198
+ config.update({
199
+ 'max_seq_length': self.max_seq_length,
200
+ 'embed_dim': self.embed_dim
201
+ })
202
+ return config
203
+
204
+
205
+ class TransformerBlock(layers.Layer):
206
+ """Transformer decoder block"""
207
+
208
+ def __init__(self, embed_dim, num_heads, ff_dim, dropout_rate=0.1, **kwargs):
209
+ super().__init__(**kwargs)
210
+ self.embed_dim = embed_dim
211
+ self.num_heads = num_heads
212
+ self.ff_dim = ff_dim
213
+ self.dropout_rate = dropout_rate
214
+
215
+ self.attention = layers.MultiHeadAttention(
216
+ num_heads=num_heads,
217
+ key_dim=embed_dim // num_heads,
218
+ dropout=dropout_rate
219
+ )
220
+ self.ffn = keras.Sequential([
221
+ layers.Dense(ff_dim, activation='gelu'),
222
+ layers.Dropout(dropout_rate),
223
+ layers.Dense(embed_dim)
224
+ ])
225
+ self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)
226
+ self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)
227
+ self.dropout1 = layers.Dropout(dropout_rate)
228
+ self.dropout2 = layers.Dropout(dropout_rate)
229
+
230
+ def causal_attention_mask(self, seq_length):
231
+ """Create causal mask for autoregressive attention"""
232
+ mask = tf.linalg.band_part(tf.ones((seq_length, seq_length)), -1, 0)
233
+ return mask
234
+
235
+ def call(self, x, training=False):
236
+ seq_length = tf.shape(x)[1]
237
+ causal_mask = self.causal_attention_mask(seq_length)
238
+
239
+ # Self-attention with causal mask
240
+ attention_output = self.attention(
241
+ query=x,
242
+ value=x,
243
+ key=x,
244
+ attention_mask=causal_mask,
245
+ training=training
246
+ )
247
+ attention_output = self.dropout1(attention_output, training=training)
248
+ x = self.layernorm1(x + attention_output)
249
+
250
+ # Feed-forward network
251
+ ffn_output = self.ffn(x)
252
+ ffn_output = self.dropout2(ffn_output, training=training)
253
+ x = self.layernorm2(x + ffn_output)
254
+
255
+ return x
256
+
257
+ def get_config(self):
258
+ config = super().get_config()
259
+ config.update({
260
+ 'embed_dim': self.embed_dim,
261
+ 'num_heads': self.num_heads,
262
+ 'ff_dim': self.ff_dim,
263
+ 'dropout_rate': self.dropout_rate
264
+ })
265
+ return config
266
+
267
+
268
+ # ============================================================
269
+ # VISIBLE LLM MODEL
270
+ # ============================================================
271
+
272
+ class VisibleLLM:
273
+ """Visible Language Model"""
274
+
275
+ def __init__(self, config=None):
276
+ self.config = config or VisibleConfig()
277
+ self.tokenizer = None
278
+ self.model = None
279
+ self.history = None
280
+
281
+ def build_model(self, vocab_size=None):
282
+ """Build the Transformer model"""
283
+ vocab_size = vocab_size or self.config.VOCAB_SIZE
284
+
285
+ print(f"\n{'='*50}")
286
+ print(f"Building {self.config.MODEL_NAME} LLM")
287
+ print(f"{'='*50}")
288
+
289
+ # Input layer
290
+ inputs = layers.Input(shape=(None,), dtype=tf.int32, name="input_ids")
291
+
292
+ # Token embedding
293
+ token_embedding = layers.Embedding(
294
+ input_dim=vocab_size,
295
+ output_dim=self.config.EMBEDDING_DIM,
296
+ name="token_embedding"
297
+ )(inputs)
298
+
299
+ # Positional encoding
300
+ x = PositionalEncoding(
301
+ self.config.MAX_SEQ_LENGTH,
302
+ self.config.EMBEDDING_DIM,
303
+ name="positional_encoding"
304
+ )(token_embedding)
305
+
306
+ # Dropout
307
+ x = layers.Dropout(self.config.DROPOUT_RATE)(x)
308
+
309
+ # Transformer blocks
310
+ for i in range(self.config.NUM_LAYERS):
311
+ x = TransformerBlock(
312
+ embed_dim=self.config.EMBEDDING_DIM,
313
+ num_heads=self.config.NUM_HEADS,
314
+ ff_dim=self.config.FF_DIM,
315
+ dropout_rate=self.config.DROPOUT_RATE,
316
+ name=f"transformer_block_{i}"
317
+ )(x)
318
+
319
+ # Final layer normalization
320
+ x = layers.LayerNormalization(epsilon=1e-6, name="final_layernorm")(x)
321
+
322
+ # Output projection
323
+ outputs = layers.Dense(vocab_size, name="output_projection")(x)
324
+
325
+ self.model = keras.Model(inputs=inputs, outputs=outputs, name=self.config.MODEL_NAME)
326
+
327
+ # Compile model
328
+ self.model.compile(
329
+ optimizer=keras.optimizers.Adam(learning_rate=self.config.LEARNING_RATE),
330
+ loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
331
+ metrics=['accuracy']
332
+ )
333
+
334
+ self.model.summary()
335
+ return self.model
336
+
337
+ def load_data(self, file_path=None):
338
+ """Load and preprocess training data"""
339
+ file_path = file_path or self.config.DATA_FILE
340
+
341
+ print(f"\nLoading data from {file_path}...")
342
+
343
+ if not os.path.exists(file_path):
344
+ raise FileNotFoundError(f"Data file not found: {file_path}")
345
+
346
+ with open(file_path, 'r', encoding='utf-8') as f:
347
+ text = f.read()
348
+
349
+ # Split into sentences/chunks
350
+ sentences = re.split(r'[.!?]+', text)
351
+ sentences = [s.strip() for s in sentences if len(s.strip()) > 10]
352
+
353
+ print(f"Loaded {len(sentences)} text segments")
354
+ return sentences
355
+
356
+ def prepare_training_data(self, texts):
357
+ """Prepare data for training"""
358
+ print("\nPreparing training data...")
359
+
360
+ # Initialize and fit tokenizer
361
+ self.tokenizer = VisibleTokenizer(vocab_size=self.config.VOCAB_SIZE)
362
+ self.tokenizer.fit(texts)
363
+
364
+ # Create training sequences
365
+ input_sequences = []
366
+ target_sequences = []
367
+
368
+ for text in texts:
369
+ token_ids = self.tokenizer.encode(
370
+ text,
371
+ max_length=self.config.MAX_SEQ_LENGTH + 1,
372
+ add_special_tokens=True
373
+ )
374
+
375
+ if len([t for t in token_ids if t != 0]) > 3: # Skip very short sequences
376
+ input_sequences.append(token_ids[:-1])
377
+ target_sequences.append(token_ids[1:])
378
+
379
+ X = np.array(input_sequences)
380
+ y = np.array(target_sequences)
381
+
382
+ print(f"Training samples: {len(X)}")
383
+ print(f"Input shape: {X.shape}")
384
+ print(f"Target shape: {y.shape}")
385
+
386
+ return X, y
387
+
388
+ def train(self, data_file=None, epochs=None, batch_size=None):
389
+ """Train the model"""
390
+ epochs = epochs or self.config.EPOCHS
391
+ batch_size = batch_size or self.config.BATCH_SIZE
392
+
393
+ # Load and prepare data
394
+ texts = self.load_data(data_file)
395
+ X, y = self.prepare_training_data(texts)
396
+
397
+ # Build model
398
+ self.build_model(vocab_size=len(self.tokenizer))
399
+
400
+ # Create model directory
401
+ os.makedirs(self.config.MODEL_DIR, exist_ok=True)
402
+
403
+ # Callbacks
404
+ callbacks = [
405
+ keras.callbacks.ModelCheckpoint(
406
+ filepath=self.config.MODEL_PATH,
407
+ save_best_only=True,
408
+ monitor='loss',
409
+ mode='min'
410
+ ),
411
+ keras.callbacks.EarlyStopping(
412
+ monitor='loss',
413
+ patience=5,
414
+ restore_best_weights=True
415
+ ),
416
+ keras.callbacks.ReduceLROnPlateau(
417
+ monitor='loss',
418
+ factor=0.5,
419
+ patience=3,
420
+ min_lr=1e-7
421
+ ),
422
+ keras.callbacks.TensorBoard(
423
+ log_dir=f'logs/{datetime.now().strftime("%Y%m%d-%H%M%S")}'
424
+ )
425
+ ]
426
+
427
+ print(f"\n{'='*50}")
428
+ print(f"Training {self.config.MODEL_NAME}")
429
+ print(f"{'='*50}")
430
+ print(f"Epochs: {epochs}")
431
+ print(f"Batch Size: {batch_size}")
432
+ print(f"{'='*50}\n")
433
+
434
+ # Train
435
+ self.history = self.model.fit(
436
+ X, y,
437
+ epochs=epochs,
438
+ batch_size=batch_size,
439
+ callbacks=callbacks,
440
+ validation_split=0.1
441
+ )
442
+
443
+ # Save tokenizer
444
+ self.tokenizer.save(self.config.TOKENIZER_PATH)
445
+
446
+ # Save config
447
+ self.save_config()
448
+
449
+ print(f"\n{'='*50}")
450
+ print(f"Training Complete!")
451
+ print(f"Model saved to: {self.config.MODEL_PATH}")
452
+ print(f"Tokenizer saved to: {self.config.TOKENIZER_PATH}")
453
+ print(f"{'='*50}\n")
454
+
455
+ return self.history
456
+
457
+ def save_config(self):
458
+ """Save model configuration"""
459
+ config_dict = {
460
+ 'model_name': self.config.MODEL_NAME,
461
+ 'version': self.config.VERSION,
462
+ 'vocab_size': len(self.tokenizer),
463
+ 'embedding_dim': self.config.EMBEDDING_DIM,
464
+ 'num_heads': self.config.NUM_HEADS,
465
+ 'num_layers': self.config.NUM_LAYERS,
466
+ 'ff_dim': self.config.FF_DIM,
467
+ 'max_seq_length': self.config.MAX_SEQ_LENGTH,
468
+ 'trained_on': datetime.now().isoformat()
469
+ }
470
+
471
+ with open(self.config.CONFIG_PATH, 'w') as f:
472
+ json.dump(config_dict, f, indent=2)
473
+
474
+ def load_model(self, model_path=None, tokenizer_path=None):
475
+ """Load a trained model"""
476
+ model_path = model_path or self.config.MODEL_PATH
477
+ tokenizer_path = tokenizer_path or self.config.TOKENIZER_PATH
478
+
479
+ print(f"Loading model from {model_path}...")
480
+
481
+ # Load tokenizer
482
+ self.tokenizer = VisibleTokenizer()
483
+ self.tokenizer.load(tokenizer_path)
484
+
485
+ # Load model with custom objects
486
+ custom_objects = {
487
+ 'PositionalEncoding': PositionalEncoding,
488
+ 'TransformerBlock': TransformerBlock
489
+ }
490
+
491
+ self.model = keras.models.load_model(model_path, custom_objects=custom_objects)
492
+ print("Model loaded successfully!")
493
+
494
+ return self
495
+
496
+ def generate(self, prompt, max_length=100, temperature=0.7, top_k=50, top_p=0.9):
497
+ """Generate text from a prompt"""
498
+ if self.model is None or self.tokenizer is None:
499
+ raise ValueError("Model not loaded. Call load_model() first.")
500
+
501
+ # Encode prompt
502
+ input_ids = self.tokenizer.encode(prompt, add_special_tokens=True)
503
+ input_ids = input_ids[:-1] # Remove end token for generation
504
+
505
+ generated_ids = list(input_ids)
506
+
507
+ for _ in range(max_length):
508
+ # Prepare input
509
+ current_input = np.array([generated_ids[-self.config.MAX_SEQ_LENGTH:]])
510
+
511
+ # Get predictions
512
+ predictions = self.model.predict(current_input, verbose=0)
513
+ next_token_logits = predictions[0, -1, :]
514
+
515
+ # Apply temperature
516
+ next_token_logits = next_token_logits / temperature
517
+
518
+ # Apply top-k filtering
519
+ if top_k > 0:
520
+ indices_to_remove = np.argsort(next_token_logits)[:-top_k]
521
+ next_token_logits[indices_to_remove] = float('-inf')
522
+
523
+ # Apply top-p (nucleus) filtering
524
+ if top_p < 1.0:
525
+ sorted_indices = np.argsort(next_token_logits)[::-1]
526
+ sorted_logits = next_token_logits[sorted_indices]
527
+ cumulative_probs = np.cumsum(tf.nn.softmax(sorted_logits).numpy())
528
+
529
+ sorted_indices_to_remove = cumulative_probs > top_p
530
+ sorted_indices_to_remove[1:] = sorted_indices_to_remove[:-1].copy()
531
+ sorted_indices_to_remove[0] = False
532
+
533
+ indices_to_remove = sorted_indices[sorted_indices_to_remove]
534
+ next_token_logits[indices_to_remove] = float('-inf')
535
+
536
+ # Sample from distribution
537
+ probs = tf.nn.softmax(next_token_logits).numpy()
538
+ next_token_id = np.random.choice(len(probs), p=probs)
539
+
540
+ # Stop if end token
541
+ if next_token_id == self.tokenizer.end_token_id:
542
+ break
543
+
544
+ generated_ids.append(next_token_id)
545
+
546
+ # Decode generated text
547
+ generated_text = self.tokenizer.decode(generated_ids, skip_special_tokens=True)
548
+
549
+ return generated_text
550
+
551
+ def chat(self, user_input, max_length=100, temperature=0.7):
552
+ """Interactive chat with the model"""
553
+ response = self.generate(
554
+ prompt=user_input,
555
+ max_length=max_length,
556
+ temperature=temperature
557
+ )
558
+ return response
559
+
560
+
561
+ # ============================================================
562
+ # FLASK WEB APPLICATION
563
+ # ============================================================
564
+
565
+ app = Flask(__name__)
566
+ visible_llm = None
567
+
568
+ # HTML Template
569
+ HTML_TEMPLATE = """
570
+ <!DOCTYPE html>
571
+ <html lang="en">
572
+ <head>
573
+ <meta charset="UTF-8">
574
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
575
+ <title>Visible LLM</title>
576
+ <style>
577
+ * {
578
+ margin: 0;
579
+ padding: 0;
580
+ box-sizing: border-box;
581
+ }
582
+
583
+ body {
584
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
585
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
586
+ min-height: 100vh;
587
+ color: #fff;
588
+ }
589
+
590
+ .container {
591
+ max-width: 900px;
592
+ margin: 0 auto;
593
+ padding: 20px;
594
+ }
595
+
596
+ header {
597
+ text-align: center;
598
+ padding: 40px 0;
599
+ }
600
+
601
+ h1 {
602
+ font-size: 3em;
603
+ background: linear-gradient(90deg, #00d2ff, #3a7bd5);
604
+ -webkit-background-clip: text;
605
+ -webkit-text-fill-color: transparent;
606
+ margin-bottom: 10px;
607
+ }
608
+
609
+ .subtitle {
610
+ color: #888;
611
+ font-size: 1.1em;
612
+ }
613
+
614
+ .chat-container {
615
+ background: rgba(255, 255, 255, 0.05);
616
+ border-radius: 20px;
617
+ padding: 30px;
618
+ margin-top: 20px;
619
+ backdrop-filter: blur(10px);
620
+ border: 1px solid rgba(255, 255, 255, 0.1);
621
+ }
622
+
623
+ .messages {
624
+ height: 400px;
625
+ overflow-y: auto;
626
+ padding: 20px;
627
+ margin-bottom: 20px;
628
+ border-radius: 15px;
629
+ background: rgba(0, 0, 0, 0.3);
630
+ }
631
+
632
+ .message {
633
+ margin-bottom: 15px;
634
+ padding: 15px 20px;
635
+ border-radius: 15px;
636
+ max-width: 80%;
637
+ animation: fadeIn 0.3s ease;
638
+ }
639
+
640
+ @keyframes fadeIn {
641
+ from { opacity: 0; transform: translateY(10px); }
642
+ to { opacity: 1; transform: translateY(0); }
643
+ }
644
+
645
+ .user-message {
646
+ background: linear-gradient(135deg, #3a7bd5, #00d2ff);
647
+ margin-left: auto;
648
+ text-align: right;
649
+ }
650
+
651
+ .bot-message {
652
+ background: rgba(255, 255, 255, 0.1);
653
+ margin-right: auto;
654
+ }
655
+
656
+ .input-area {
657
+ display: flex;
658
+ gap: 15px;
659
+ }
660
+
661
+ #userInput {
662
+ flex: 1;
663
+ padding: 15px 20px;
664
+ border: none;
665
+ border-radius: 15px;
666
+ background: rgba(255, 255, 255, 0.1);
667
+ color: #fff;
668
+ font-size: 1em;
669
+ outline: none;
670
+ transition: all 0.3s ease;
671
+ }
672
+
673
+ #userInput:focus {
674
+ background: rgba(255, 255, 255, 0.15);
675
+ box-shadow: 0 0 20px rgba(0, 210, 255, 0.2);
676
+ }
677
+
678
+ #userInput::placeholder {
679
+ color: #888;
680
+ }
681
+
682
+ button {
683
+ padding: 15px 30px;
684
+ border: none;
685
+ border-radius: 15px;
686
+ background: linear-gradient(135deg, #3a7bd5, #00d2ff);
687
+ color: #fff;
688
+ font-size: 1em;
689
+ cursor: pointer;
690
+ transition: all 0.3s ease;
691
+ }
692
+
693
+ button:hover {
694
+ transform: translateY(-2px);
695
+ box-shadow: 0 10px 30px rgba(0, 210, 255, 0.3);
696
+ }
697
+
698
+ button:disabled {
699
+ opacity: 0.5;
700
+ cursor: not-allowed;
701
+ transform: none;
702
+ }
703
+
704
+ .settings {
705
+ display: grid;
706
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
707
+ gap: 15px;
708
+ margin-bottom: 20px;
709
+ padding: 20px;
710
+ background: rgba(0, 0, 0, 0.2);
711
+ border-radius: 15px;
712
+ }
713
+
714
+ .setting-group {
715
+ display: flex;
716
+ flex-direction: column;
717
+ gap: 5px;
718
+ }
719
+
720
+ .setting-group label {
721
+ font-size: 0.9em;
722
+ color: #888;
723
+ }
724
+
725
+ .setting-group input[type="range"] {
726
+ width: 100%;
727
+ }
728
+
729
+ .setting-value {
730
+ text-align: center;
731
+ font-size: 0.9em;
732
+ color: #00d2ff;
733
+ }
734
+
735
+ .status {
736
+ text-align: center;
737
+ padding: 10px;
738
+ border-radius: 10px;
739
+ margin-bottom: 20px;
740
+ }
741
+
742
+ .status.ready {
743
+ background: rgba(0, 255, 0, 0.1);
744
+ color: #00ff00;
745
+ }
746
+
747
+ .status.loading {
748
+ background: rgba(255, 255, 0, 0.1);
749
+ color: #ffff00;
750
+ }
751
+
752
+ .status.error {
753
+ background: rgba(255, 0, 0, 0.1);
754
+ color: #ff0000;
755
+ }
756
+
757
+ .loading-spinner {
758
+ display: inline-block;
759
+ width: 20px;
760
+ height: 20px;
761
+ border: 2px solid #fff;
762
+ border-radius: 50%;
763
+ border-top-color: transparent;
764
+ animation: spin 1s linear infinite;
765
+ }
766
+
767
+ @keyframes spin {
768
+ to { transform: rotate(360deg); }
769
+ }
770
+ </style>
771
+ </head>
772
+ <body>
773
+ <div class="container">
774
+ <header>
775
+ <h1>🔮 Visible</h1>
776
+ <p class="subtitle">Intelligent Language Model powered by TensorFlow</p>
777
+ </header>
778
+
779
+ <div class="chat-container">
780
+ <div id="status" class="status loading">Checking model status...</div>
781
+
782
+ <div class="settings">
783
+ <div class="setting-group">
784
+ <label>Temperature</label>
785
+ <input type="range" id="temperature" min="0.1" max="2" step="0.1" value="0.7">
786
+ <span class="setting-value" id="tempValue">0.7</span>
787
+ </div>
788
+ <div class="setting-group">
789
+ <label>Max Length</label>
790
+ <input type="range" id="maxLength" min="10" max="200" step="10" value="100">
791
+ <span class="setting-value" id="lengthValue">100</span>
792
+ </div>
793
+ <div class="setting-group">
794
+ <label>Top-K</label>
795
+ <input type="range" id="topK" min="1" max="100" step="1" value="50">
796
+ <span class="setting-value" id="topKValue">50</span>
797
+ </div>
798
+ <div class="setting-group">
799
+ <label>Top-P</label>
800
+ <input type="range" id="topP" min="0.1" max="1" step="0.1" value="0.9">
801
+ <span class="setting-value" id="topPValue">0.9</span>
802
+ </div>
803
+ </div>
804
+
805
+ <div class="messages" id="messages">
806
+ <div class="message bot-message">
807
+ Hello! I am Visible, your AI assistant. Ask me anything!
808
+ </div>
809
+ </div>
810
+
811
+ <div class="input-area">
812
+ <input type="text" id="userInput" placeholder="Type your message..." autocomplete="off">
813
+ <button id="sendBtn" onclick="sendMessage()">Send</button>
814
+ </div>
815
+ </div>
816
+ </div>
817
+
818
+ <script>
819
+ // Update setting values display
820
+ document.querySelectorAll('input[type="range"]').forEach(input => {
821
+ input.addEventListener('input', function() {
822
+ document.getElementById(this.id + 'Value' === 'temperatureValue' ? 'tempValue' :
823
+ this.id === 'maxLength' ? 'lengthValue' :
824
+ this.id === 'topK' ? 'topKValue' : 'topPValue').textContent = this.value;
825
+ });
826
+ });
827
+
828
+ // Fix the value display IDs
829
+ document.getElementById('temperature').addEventListener('input', function() {
830
+ document.getElementById('tempValue').textContent = this.value;
831
+ });
832
+ document.getElementById('maxLength').addEventListener('input', function() {
833
+ document.getElementById('lengthValue').textContent = this.value;
834
+ });
835
+ document.getElementById('topK').addEventListener('input', function() {
836
+ document.getElementById('topKValue').textContent = this.value;
837
+ });
838
+ document.getElementById('topP').addEventListener('input', function() {
839
+ document.getElementById('topPValue').textContent = this.value;
840
+ });
841
+
842
+ // Check status
843
+ async function checkStatus() {
844
+ try {
845
+ const response = await fetch('/api/status');
846
+ const data = await response.json();
847
+ const statusEl = document.getElementById('status');
848
+
849
+ if (data.model_loaded) {
850
+ statusEl.className = 'status ready';
851
+ statusEl.textContent = '✓ Model Ready - ' + data.model_name;
852
+ } else {
853
+ statusEl.className = 'status error';
854
+ statusEl.textContent = '✗ Model not loaded. Please train the model first.';
855
+ }
856
+ } catch (e) {
857
+ document.getElementById('status').className = 'status error';
858
+ document.getElementById('status').textContent = '✗ Server connection failed';
859
+ }
860
+ }
861
+
862
+ checkStatus();
863
+
864
+ // Send message
865
+ async function sendMessage() {
866
+ const input = document.getElementById('userInput');
867
+ const message = input.value.trim();
868
+
869
+ if (!message) return;
870
+
871
+ const messagesDiv = document.getElementById('messages');
872
+ const sendBtn = document.getElementById('sendBtn');
873
+
874
+ // Add user message
875
+ messagesDiv.innerHTML += `<div class="message user-message">${message}</div>`;
876
+ input.value = '';
877
+
878
+ // Disable button and show loading
879
+ sendBtn.disabled = true;
880
+ sendBtn.innerHTML = '<span class="loading-spinner"></span>';
881
+
882
+ // Scroll to bottom
883
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
884
+
885
+ try {
886
+ const response = await fetch('/api/generate', {
887
+ method: 'POST',
888
+ headers: { 'Content-Type': 'application/json' },
889
+ body: JSON.stringify({
890
+ prompt: message,
891
+ max_length: parseInt(document.getElementById('maxLength').value),
892
+ temperature: parseFloat(document.getElementById('temperature').value),
893
+ top_k: parseInt(document.getElementById('topK').value),
894
+ top_p: parseFloat(document.getElementById('topP').value)
895
+ })
896
+ });
897
+
898
+ const data = await response.json();
899
+
900
+ if (data.success) {
901
+ messagesDiv.innerHTML += `<div class="message bot-message">${data.response}</div>`;
902
+ } else {
903
+ messagesDiv.innerHTML += `<div class="message bot-message" style="color: #ff6b6b">Error: ${data.error}</div>`;
904
+ }
905
+ } catch (e) {
906
+ messagesDiv.innerHTML += `<div class="message bot-message" style="color: #ff6b6b">Error: Failed to connect to server</div>`;
907
+ }
908
+
909
+ // Re-enable button
910
+ sendBtn.disabled = false;
911
+ sendBtn.innerHTML = 'Send';
912
+
913
+ // Scroll to bottom
914
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
915
+ }
916
+
917
+ // Handle Enter key
918
+ document.getElementById('userInput').addEventListener('keypress', function(e) {
919
+ if (e.key === 'Enter') {
920
+ sendMessage();
921
+ }
922
+ });
923
+ </script>
924
+ </body>
925
+ </html>
926
+ """
927
+
928
+
929
+ @app.route('/')
930
+ def home():
931
+ """Render the main chat interface"""
932
+ return render_template_string(HTML_TEMPLATE)
933
+
934
+
935
+ @app.route('/api/status')
936
+ def status():
937
+ """Get model status"""
938
+ global visible_llm
939
+ return jsonify({
940
+ 'model_loaded': visible_llm is not None and visible_llm.model is not None,
941
+ 'model_name': VisibleConfig.MODEL_NAME,
942
+ 'version': VisibleConfig.VERSION
943
+ })
944
+
945
+
946
+ @app.route('/api/generate', methods=['POST'])
947
+ def generate():
948
+ """Generate text from prompt"""
949
+ global visible_llm
950
+
951
+ if visible_llm is None or visible_llm.model is None:
952
+ return jsonify({
953
+ 'success': False,
954
+ 'error': 'Model not loaded. Please train the model first.'
955
+ })
956
+
957
+ try:
958
+ data = request.json
959
+ prompt = data.get('prompt', '')
960
+ max_length = data.get('max_length', 100)
961
+ temperature = data.get('temperature', 0.7)
962
+ top_k = data.get('top_k', 50)
963
+ top_p = data.get('top_p', 0.9)
964
+
965
+ response = visible_llm.generate(
966
+ prompt=prompt,
967
+ max_length=max_length,
968
+ temperature=temperature,
969
+ top_k=top_k,
970
+ top_p=top_p
971
+ )
972
+
973
+ return jsonify({
974
+ 'success': True,
975
+ 'response': response,
976
+ 'prompt': prompt
977
+ })
978
+
979
+ except Exception as e:
980
+ return jsonify({
981
+ 'success': False,
982
+ 'error': str(e)
983
+ })
984
+
985
+
986
+ @app.route('/api/train', methods=['POST'])
987
+ def train_model():
988
+ """Train the model (API endpoint)"""
989
+ global visible_llm
990
+
991
+ try:
992
+ data = request.json or {}
993
+ epochs = data.get('epochs', 50)
994
+ batch_size = data.get('batch_size', 32)
995
+
996
+ visible_llm = VisibleLLM()
997
+ visible_llm.train(epochs=epochs, batch_size=batch_size)
998
+
999
+ return jsonify({
1000
+ 'success': True,
1001
+ 'message': 'Training complete!'
1002
+ })
1003
+
1004
+ except Exception as e:
1005
+ return jsonify({
1006
+ 'success': False,
1007
+ 'error': str(e)
1008
+ })
1009
+
1010
+
1011
+ # ============================================================
1012
+ # COMMAND LINE INTERFACE
1013
+ # ============================================================
1014
+
1015
+ def main():
1016
+ """Main entry point"""
1017
+ import argparse
1018
+
1019
+ parser = argparse.ArgumentParser(description='Visible LLM - Language Model')
1020
+ parser.add_argument('--train', action='store_true', help='Train the model')
1021
+ parser.add_argument('--serve', action='store_true', help='Start web server')
1022
+ parser.add_argument('--chat', action='store_true', help='Interactive chat mode')
1023
+ parser.add_argument('--epochs', type=int, default=50, help='Number of training epochs')
1024
+ parser.add_argument('--batch-size', type=int, default=32, help='Batch size')
1025
+ parser.add_argument('--data', type=str, default='veda.txt', help='Training data file')
1026
+ parser.add_argument('--port', type=int, default=5000, help='Server port')
1027
+
1028
+ args = parser.parse_args()
1029
+
1030
+ global visible_llm
1031
+
1032
+ if args.train:
1033
+ print("\n" + "="*60)
1034
+ print("VISIBLE LLM - TRAINING MODE")
1035
+ print("="*60 + "\n")
1036
+
1037
+ visible_llm = VisibleLLM()
1038
+ VisibleConfig.DATA_FILE = args.data
1039
+ visible_llm.train(epochs=args.epochs, batch_size=args.batch_size)
1040
+
1041
+ elif args.chat:
1042
+ print("\n" + "="*60)
1043
+ print("VISIBLE LLM - CHAT MODE")
1044
+ print("="*60 + "\n")
1045
+
1046
+ visible_llm = VisibleLLM()
1047
+ visible_llm.load_model()
1048
+
1049
+ print("Chat with Visible (type 'quit' to exit)\n")
1050
+
1051
+ while True:
1052
+ user_input = input("You: ").strip()
1053
+ if user_input.lower() in ['quit', 'exit', 'q']:
1054
+ print("Goodbye!")
1055
+ break
1056
+
1057
+ if user_input:
1058
+ response = visible_llm.chat(user_input)
1059
+ print(f"Visible: {response}\n")
1060
+
1061
+ elif args.serve:
1062
+ print("\n" + "="*60)
1063
+ print("VISIBLE LLM - WEB SERVER MODE")
1064
+ print("="*60 + "\n")
1065
+
1066
+ # Try to load existing model
1067
+ visible_llm = VisibleLLM()
1068
+ try:
1069
+ visible_llm.load_model()
1070
+ print("Model loaded successfully!")
1071
+ except Exception as e:
1072
+ print(f"Could not load model: {e}")
1073
+ print("Please train the model first with: python app.py --train")
1074
+ visible_llm = None
1075
+
1076
+ print(f"\nStarting server on http://localhost:{args.port}")
1077
+ app.run(host='0.0.0.0', port=args.port, debug=False)
1078
+
1079
+ else:
1080
+ # Default: show help
1081
+ parser.print_help()
1082
+ print("\n" + "="*60)
1083
+ print("QUICK START:")
1084
+ print("="*60)
1085
+ print("1. Train the model: python app.py --train --data veda.txt")
1086
+ print("2. Start web server: python app.py --serve")
1087
+ print("3. Interactive chat: python app.py --chat")
1088
+ print("="*60 + "\n")
1089
+
1090
+
1091
+ if __name__ == '__main__':
1092
+ main()