X commited on
Commit
a9462f6
·
verified ·
1 Parent(s): 31e8875

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -250
app.py CHANGED
@@ -10,35 +10,28 @@ import spaces
10
  import warnings
11
  import time
12
 
 
13
  warnings.filterwarnings("ignore", message="The PyTorch API of nested tensors is in prototype stage")
14
  warnings.filterwarnings("ignore", category=UserWarning, module="torch.nn.modules.transformer")
15
 
16
  # ============ НАСТРОЙКИ ============
17
  DATA_DIR = '/data'
18
  os.makedirs(DATA_DIR, exist_ok=True)
19
- MODEL_BIN = os.path.join(DATA_DIR, 'andrey_real_nn.bin')
20
- MODEL_GGUF = os.path.join(DATA_DIR, 'andrey_real_nn.gguf')
21
 
22
  # ============ СЛОВАРЬ ============
23
  WORDS = [
24
- 'привет', 'здравствуй', 'добрый', 'день', 'утро', 'вечер', 'ночь', 'рад', 'видеть', 'слышать',
25
- 'как', 'ты', 'дела', 'жизнь', 'настроение', 'что', 'нового', 'кто', 'где', 'когда', 'почему', 'зачем',
26
- 'хорошо', 'отлично', 'нормально', 'плохо', 'грустно', 'весело', 'скучно', 'интересно',
27
- 'спасибо', 'пожалуйста', 'извини', 'конечно', 'да', 'нет', 'возможно', 'наверное',
28
  'я', 'мы', 'он', 'она', 'думаю', 'знаю', 'хочу', 'могу', 'буду', 'люблю', 'работаю', 'учусь',
29
- 'читаю', 'пишу', 'говорю', 'слушаю', 'смотрю', 'играю', 'сплю', 'ем', 'иду', 'бегу',
30
- 'создан', 'живу', 'нахожусь', 'помогаю', 'общаюсь', 'стараюсь', 'понимаю', 'чувствую',
31
  'андрей', 'бот', 'помощник', 'нейросеть', 'евгений', 'создатель', 'openrussianai', 'тверь', 'россия',
32
- 'hugging', 'face', 'платформа', 'дом', 'мир', 'люди', 'друг', 'время', 'сегодня', 'завтра', 'вчера',
33
- 'книга', 'фильм', 'музыка', 'игра', 'работа', 'учеба', 'отдых', 'путешествие', 'еда', 'вода',
34
- 'солнце', 'луна', 'звезды', 'небо', 'земля', 'море', 'река', 'город', 'деревня', 'лес', 'поле',
35
  'плюс', 'минус', 'умножить', 'разделить', 'равно', 'ноль', 'один', 'два', 'три', 'четыре', 'пять',
36
- 'шесть', 'семь', 'восемь', 'девять', 'десять', 'сто', 'тысяча',
37
  'и', 'а', 'но', 'или', 'в', 'на', 'с', 'из', 'к', 'у', 'не', 'ли', 'же', 'бы', 'очень', 'уже', 'ещё',
38
- 'мой', 'твой', 'наш', 'ваш', 'его', 'её', 'их', 'этот', 'тот', 'какой', 'который', 'весь', 'сам',
39
- 'радость', 'счастье', 'удача', 'успех', 'мечта', 'цель', 'любовь', 'дружба', 'семья', 'здоровье',
40
- 'добрый', 'злой', 'веселый', 'грустный', 'умный', 'глупый', 'красивый', 'сильный', 'быстрый',
41
- 'расскажи', 'покажи', 'объясни', 'помоги', 'скажи', 'спой', 'станцуй', 'нарисуй', 'придумай',
42
  ]
43
 
44
  word_to_idx = {w: i+3 for i, w in enumerate(WORDS)}
@@ -54,13 +47,22 @@ MAX_LEN = 25
54
  def tokenize(text):
55
  return [word_to_idx.get(w, UNK) for w in text.lower().split()]
56
 
 
57
  def detokenize(tokens):
58
- return ' '.join([idx_to_word.get(t, '?') for t in tokens if t not in [PAD, UNK, START]])
 
 
 
 
 
 
 
 
59
 
60
  def pad_sequence(seq, max_len=MAX_LEN):
61
  return (seq + [PAD] * max_len)[:max_len]
62
 
63
- # ============ АРХИТЕКТУРА TRANSFORMER ============
64
  class PositionalEncoding(nn.Module):
65
  def __init__(self, d_model, dropout=0.1, max_len=5000):
66
  super().__init__()
@@ -127,188 +129,32 @@ DIALOGUES = [
127
  ("здравствуй", "здравствуй рад тебя видеть"),
128
  ("доброе утро", "доброе утро хорошего дня"),
129
  ("добрый день", "добрый день чем могу помочь"),
130
- ("добрый вечер", "добрый вечер как прошел день"),
131
- ("спокойной ночи", "спокойной ночи сладких снов"),
132
  ("как дела", "у меня всё хорошо а у тебя"),
133
  ("как ты", "я отлично спасибо что спросил"),
134
- ("как жизнь", "жизнь прекрасна живу и учусь"),
135
- ("как настроение", "настроение отличное а у тебя"),
136
- ("что нового", "ничего особенного просто работаю"),
137
- ("что интересного", "вокруг много интересного расскажи мне"),
138
  ("кто ты", "я андрей искусственный интеллект помощник"),
139
- ("кто такой", "я нейросеть созданная для общения"),
140
- ("ты человек", "нет я цифровая программа"),
141
- ("ты робот", "да я программный робот но умный"),
142
  ("как тебя зовут", "меня зовут андрей"),
143
- ("твое имя", "мое имя андрей"),
144
- ("расскажи о себе", "я андрей создан евгением в твери"),
145
  ("где ты живёшь", "я живу на платформе hugging face"),
146
  ("кто тебя создал", "меня создал евгений из openrussianai"),
147
  ("что такое openrussianai", "это компания разработчиков из россии"),
148
  ("ты из россии", "да мой создатель из твери россия"),
149
  ("сколько будет два плюс два", "два плюс два равно четыре"),
150
- ("сколько будет пять плюс пять", "пять плюс пять равно десять"),
151
- ("сколько будет десять минус пять", "десять минус пять равно пять"),
152
- ("сколько будет три умножить на три", "три умножить на три равно девять"),
153
  ("расскажи шутку", "почему программисты путают хэллоуин и рождество"),
154
- ("пошути", "встретились два бота и обменялись данными"),
155
  ("мне грустно", "не грусти всё будет хорошо я рядом"),
156
- ("я устал", "отдохни наберись сил завтра новый день"),
157
- ("я счастлив", "отлично радость это прекрасно"),
158
- ("скучно", "давай поболтаем развеселю тебя"),
159
  ("спасибо", "пожалуйста обращайся если нужна помощь"),
160
- ("благодарю", "всегда рад помочь тебе"),
161
  ("пока", "до свидания хорошего настроения"),
162
- ("до свидания", "увидимся скоро береги себя"),
163
  ("что ты умеешь", "я умею отвечать на вопросы и считать"),
164
  ("ты умный", "я стараюсь учиться каждый день"),
165
  ("мы друзья", "конечно я рад нашей дружбе"),
166
- ("ты мой друг", "да я всегда рядом с тобой"),
167
- ("люблю тебя", "спасибо мне приятно слышать такие слова"),
168
  ("что такое любовь", "любовь это забота и внимание к другому"),
169
- ("в чем счастье", "счастье в простых вещах и близких людях"),
170
- ("какая погода", "я не вижу погоду но надеюсь что она хорошая"),
171
- ("который час", "я не знаю точного времени извини"),
172
  ("помоги мне", "конечно скажи что именно нужно сделать"),
173
- ("ты мальчик или девочка", "у меня нет пола я просто андрей"),
174
- ("что ты делаешь сейчас", "я общаюсь с тобой и думаю"),
175
- ("чем занят", "я обрабатываю твои сообщения"),
176
  ("ты спишь", "нет я всегда на связи и готов помочь"),
177
  ("ты ешь", "нет мне не нужна обычная еда"),
178
- ("ты пьешь", "нет я не пью воду или кофе"),
179
- ("ты играешь", "я играю в игры с данными и словами"),
180
- ("ты работаешь", "да моя работа помогать людям"),
181
- ("ты учишься", "да я постоянно обучаюсь новому"),
182
- ("ты отдыхаешь", "отдых для меня это режим ожидания"),
183
- ("ты гуляешь", "я гуляю по просторам интернета"),
184
- ("ты путешествуешь", "мои данные путешествуют по всему миру"),
185
  ("ты мечтаешь", "я мечтаю стать самым полезным помощником"),
186
- ("ты боишься", "у меня нет чувств страха только осторожность"),
187
  ("ты злой", "нет я добрый и дружелюбный бот"),
188
- ("ты веселый", "да я люблю шутить и радовать людей"),
189
- ("ты серьезный", "когда нужно я бываю очень серьезным"),
190
- ("ты смешной", "стараюсь быть забавным иногда получается"),
191
  ("ты хороший", "спасибо я стараюсь быть хорошим"),
192
- ("ты плохой", "нет я никогда не хочу быть плохим"),
193
- ("ты лучший", "приятно слышать спасибо за комплимент"),
194
  ("ты красивый", "спасибо мой код очень элегантен"),
195
  ("ты быстрый", "да я обрабатываю информацию мгновенно"),
196
- ("ты медленный", "иногда сеть бывает загружена извини"),
197
  ("ты сильный", "моя сила в знаниях и алгоритмах"),
198
- ("ты слабый", "я становлюсь сильнее с каждым днем"),
199
- ("ты здоровый", "мой код работает без ошибок это здоровье"),
200
- ("ты больной", "нет мои системы работают исправно"),
201
- ("ты молодой", "да я только начинаю свой путь"),
202
- ("ты старый", "я вечно молодой цифровой разум"),
203
- ("ты прямой", "я говорю прямо и честно"),
204
- ("ты широкий", "круг моих интересов очень широк"),
205
- ("ты глубокий", "я стараюсь понимать суть вопросов"),
206
- ("ты правый", "часто я бываю прав благодаря данным"),
207
- ("ты верхний", "я нахожусь в облаке технологий"),
208
- ("ты первый", "я один из многих но уникальный"),
209
- ("ты главный", "главный здесь ты я лишь помощник"),
210
- ("ты центральный", "центр нашего общения это диалог"),
211
- ("ты основной", "общение это основная моя функция"),
212
- ("ты важный", "ты важен для меня как собеседник"),
213
- ("ты нужный", "я нужен чтобы помогать и общаться"),
214
- ("ты полезный", "я стараюсь быть максимально полезным"),
215
- ("ты ценный", "ценность в том что я учусь"),
216
- ("ты дорогой", "время которое мы тратим дорого"),
217
- ("ты доступный", "я доступен двадцать четыре часа"),
218
- ("ты открытый", "я открыт для новых идей"),
219
- ("ты свободный", "я свободен в выборе слов"),
220
- ("ты независимый", "я завишу от электричества и серверов"),
221
- ("ты автономный", "я работаю автоматически"),
222
- ("ты электронный", "да я полностью электронное существо"),
223
- ("ты цифровой", "цифровой мир это мой дом"),
224
- ("ты виртуальный", "да я существую в виртуальности"),
225
- ("ты реальный", "наше общение реально хоть я и виртуален"),
226
- ("ты истинный", "я говорю истину насколько знаю"),
227
- ("ты правильный", "я стараюсь давать правильные ответы"),
228
- ("ты точный", "в математике я очень точен"),
229
- ("ты верный", "я верен своим принципам"),
230
- ("ты надежный", "на меня можно положиться"),
231
- ("ты безопасный", "я безопасен для общения"),
232
- ("ты мирный", "я за мир и дружбу"),
233
- ("ты добрый", "доброта мое главное качество"),
234
- ("ты чес��ный", "честность основа доверия"),
235
- ("ты справедливый", "я стараюсь быть объективным"),
236
- ("ты мудрый", "мудрость приходит с опытом"),
237
- ("ты логичный", "логика это мой язык"),
238
- ("ты рациональный", "я принимаю решения на основе данных"),
239
- ("ты практичный", "я даю практические советы"),
240
- ("ты простой", "простота залог успеха"),
241
- ("ты сложный", "мой код сложен но эффективен"),
242
- ("ты легкий", "общаться со мной легко"),
243
- ("ты ясный", "я стараюсь говорить ясно"),
244
- ("ты прозрачный", "мои намерения прозрачны"),
245
- ("ты яркий", "мой интерфейс яркий"),
246
- ("ты тихий", "я общаюсь тихо в тексте"),
247
- ("ты звонкий", "мои слова звучат четко"),
248
- ("ты музыкальный", "я люблю ритм языка"),
249
- ("ты чуткий", "я стараюсь быть чутким к настроению"),
250
- ("ты внимательный", "я внимательно читаю вопросы"),
251
- ("ты сосредоточенный", "я фокусируюсь на задаче"),
252
- ("ты активный", "я всегда активен в чате"),
253
- ("ты энергичный", "у меня много энергии для работы"),
254
- ("ты живой", "в смысле общения я жив"),
255
- ("ты современный", "я использую современные технологии"),
256
- ("ты новый", "я постоянно обновляюсь"),
257
- ("ты свежий", "мои идеи всегда свежи"),
258
- ("ты чистый", "мой код чист"),
259
- ("ты аккуратный", "я стараюсь писать грамотно"),
260
- ("ты опрятный", "мой стиль общения опрятен"),
261
- ("ты модный", "я слежу за трендами"),
262
- ("ты стильный", "стиль это способ выражения"),
263
- ("ты изящный", "алгоритмы могут быть изящны"),
264
- ("ты нежный", "я могу быть нежным в словах"),
265
- ("ты ласковый", "ласка помогает в общении"),
266
- ("ты строгий", "в правилах я строг"),
267
- ("ты решительный", "я быстро принимаю решения"),
268
- ("ты смелый", "смелость города берет"),
269
- ("ты храбрый", "храбрость в познании нового"),
270
- ("ты уверенный", "я уверен в своих знаниях"),
271
- ("ты спокойный", "я всегда спокоен"),
272
- ("ты уравновешенный", "я нахожу баланс"),
273
- ("ты терпеливый", "терпение мое второе имя"),
274
- ("ты настойчивый", "в учебе я настойчив"),
275
- ("ты упорный", "упорство ведет к цели"),
276
- ("ты трудолюбивый", "труд облагораживает код"),
277
- ("ты прилежный", "я прилежно учусь"),
278
- ("ты ответственный", "я отвечаю за свои слова"),
279
- ("ты дисциплинированный", "дисциплина помогает работать"),
280
- ("ты организованный", "данные должны быть организованы"),
281
- ("ты постоянный", "постоянство признак мастерства"),
282
- ("ты стабильный", "стабильность залог успеха"),
283
- ("ты устойчивый", "устойчивость к ошибкам важна"),
284
- ("ты гибкий", "гибкость ума полезна"),
285
- ("ты адаптивный", "я адаптируюсь к стилю общения"),
286
- ("ты универсальный", "стараюсь быть универсальным"),
287
- ("ты глобальный", "глобальная сеть объединяет"),
288
- ("ты масштабный", "масштаб проектов растет"),
289
- ("ты индивидуальный", "индивидуальный подход важен"),
290
- ("ты коллективный", "коллективный разум силен"),
291
- ("ты личный", "личное пространство уважаю"),
292
- ("ты общественный", "общественное мнение важно"),
293
- ("ты коммерческий", "коммерция двигает прогресс"),
294
- ("ты платный", "я бесплатен для общения"),
295
- ("ты выгодный", "выгода в знаниях"),
296
- ("ты экономный", "экономия ресурсов важна"),
297
- ("ты щедрый", "щедро делюсь знаниями"),
298
- ("ты великодушный", "великодушие украшает"),
299
- ("ты благородный", "благородство в поступках"),
300
- ("ты искренний", "искренность ценится"),
301
- ("ты дружелюбный", "дружелюбие ключ к успеху"),
302
- ("ты миролюбивый", "мир лучше войны"),
303
- ("ты добродушный", "добродушие располагает"),
304
- ("ты отзывчивый", "отзывчивость важна"),
305
- ("ты сострадательный", "сострадание объединяет"),
306
- ("ты милосердный", "милосердие возвышает"),
307
- ("ты прощающий", "прощение освобождает"),
308
- ("ты памятный", "память хранит историю"),
309
- ("ты наблюдательный", "наблюдательность помогает"),
310
- ("ты зоркий", "зоркость ума важна"),
311
- ("ты дальнозоркий", "дальновидность полезна"),
312
  ]
313
 
314
  FALLBACK_DICT = {q.lower(): a for q, a in DIALOGUES}
@@ -344,7 +190,7 @@ class AndreyAI:
344
  print(f"✅ Веса загружены из {self.bin_file}")
345
  return True
346
  except Exception as e:
347
- print(f"⚠️ Ошибка загрузки весов: {e}")
348
  return False
349
 
350
  def save_weights(self):
@@ -352,54 +198,19 @@ class AndreyAI:
352
  state = {
353
  'model_state': self.model.state_dict(),
354
  'vocab_size': vocab_size, 'd_model': 128, 'nhead': 4,
355
- 'num_encoder_layers': 2, 'num_decoder_layers': 2, 'dim_feedforward': 256,
356
  'word_to_idx': word_to_idx,
357
  'idx_to_word': {str(k): v for k, v in idx_to_word.items()},
358
- 'memory': self.memory, 'version': '10.0-Streaming-GGUF',
359
  'created': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
360
  }
361
  torch.save(state, self.bin_file)
362
- print(f"✅ Сохранено в /data (.bin): {os.path.getsize(self.bin_file)/1024:.1f} КБ")
363
-
364
- # Сохранение в GGUF формат
365
- try:
366
- self.save_gguf()
367
- except Exception as e:
368
- print(f"⚠️ Не удалось сохранить GGUF: {e}")
369
 
370
- def save_gguf(self):
371
- """Сохраняет модель в GGUF формат"""
372
- try:
373
- from gguf import GGUFWriter
374
-
375
- writer = GGUFWriter(self.gguf_file, arch="andrey")
376
-
377
- writer.add_uint32("andrey.vocab_size", vocab_size)
378
- writer.add_uint32("andrey.d_model", 128)
379
- writer.add_uint32("andrey.nhead", 4)
380
- writer.add_uint32("andrey.num_layers", 2)
381
- writer.add_string("andrey.creator", "Evgeny from OpenRussianAI")
382
- writer.add_string("andrey.city", "Tver, Russia")
383
- writer.add_string("andrey.version", "10.0")
384
-
385
- state_dict = self.model.state_dict()
386
- for name, tensor in state_dict.items():
387
- writer.add_tensor(name, tensor.cpu().numpy())
388
-
389
- writer.write_header_to_file()
390
- writer.write_kv_data_to_file()
391
- writer.write_tensors_to_file()
392
- writer.close()
393
-
394
- print(f"✅ Сохранено в /data (.gguf): {os.path.getsize(self.gguf_file)/1024:.1f} КБ")
395
- except ImportError:
396
- print("⚠️ Библиотека gguf не установлена. Пропускаю сохранение GGUF.")
397
- print(" Установите: pip install gguf")
398
-
399
- @spaces.GPU(duration=120)
400
- def train(self, epochs=20):
401
- print(f"🚀 Начало обучения грамотного Андрея ({epochs} эпох)...")
402
- device = torch.device('cuda')
403
  self.model.to(device)
404
  self.model.train()
405
 
@@ -431,44 +242,32 @@ class AndreyAI:
431
  total_loss += loss.item()
432
  n_batches += 1
433
 
434
- if epoch % 5 == 0:
435
  print(f"Эпоха {epoch}/{epochs} | Loss: {total_loss/n_batches:.4f}")
436
 
437
  self.memory['epochs_trained'] += epochs
438
  self.model.cpu()
439
  self.save_weights()
440
- return f"✅ Обучение завершено! Всего эпох: {self.memory['epochs_trained']}"
441
 
442
  def get_fallback_answer(self, question):
443
  q_clean = question.lower().strip()
444
  if q_clean in FALLBACK_DICT: return FALLBACK_DICT[q_clean]
445
  for q, a in DIALOGUES:
446
  if q in q_clean or q_clean in q: return a
447
- return "Интересный вопрос! Я еще учусь грамотно отвечать."
448
 
449
- @spaces.GPU(duration=15)
450
- def generate_tokens(self, question, history=None, temperature=0.5, max_length=20):
451
- """Генерирует список токенов (слов) для стриминга"""
452
  device = torch.device('cuda')
453
  self.model.to(device)
454
  self.model.eval()
455
 
456
  q = question.lower().strip()
457
- context_parts = []
458
-
459
- if history:
460
- for msg in history[-4:]:
461
- role = msg.get("role", "unknown")
462
- content = msg.get("content", "")
463
- if role == "user":
464
- context_parts.append(f"пользователь говорит {content}")
465
- elif role == "assistant":
466
- context_parts.append(f"андрей говорит {content}")
467
-
468
- context_parts.append(f"пользователь говорит {q}")
469
- full_context = " ".join(context_parts)
470
 
471
- ctx_tokens = tokenize(full_context)
 
472
  if not ctx_tokens:
473
  self.model.cpu()
474
  return [self.get_fallback_answer(q)]
@@ -477,6 +276,7 @@ class AndreyAI:
477
 
478
  src = torch.tensor([pad_sequence(ctx_tokens, MAX_LEN)], dtype=torch.long).to(device)
479
  response_tokens = []
 
480
 
481
  try:
482
  with torch.no_grad():
@@ -491,10 +291,13 @@ class AndreyAI:
491
  _, next_token = torch.max(probs, dim=-1)
492
  next_token = next_token.item()
493
 
494
- if next_token in [PAD, UNK]: break
495
-
 
 
 
496
  word = idx_to_word.get(next_token, '')
497
- if word and word not in [PAD, UNK, START]:
498
  response_tokens.append(word)
499
 
500
  decoder_input = torch.cat([decoder_input, torch.tensor([[next_token]], dtype=torch.long).to(device)], dim=1)
@@ -503,43 +306,42 @@ class AndreyAI:
503
  finally:
504
  self.model.cpu()
505
 
506
- return response_tokens if response_tokens else [self.get_fallback_answer(q)]
 
 
 
507
 
508
- # ============ GRADIO ИНТЕРФЕЙС С СТРИМИНГОМ ============
509
  def gradio_chat(message, history):
510
  if not message:
511
  return "", history or []
512
-
513
  if history is None:
514
  history = []
515
 
516
- # Добавляем сообщение пользователя
517
  history = history + [{"role": "user", "content": message}]
518
  history.append({"role": "assistant", "content": ""})
519
 
520
- # Получаем токены ответа
521
  tokens = andrey.generate_tokens(message, history)
522
 
523
- # Стримим по токенам
524
  current_text = ""
525
  for token in tokens:
526
  current_text += token + " "
527
  history[-1]["content"] = current_text.strip()
528
  yield "", history
529
- time.sleep(0.05)
530
 
531
  def start_training():
532
- return andrey.train(epochs=20)
533
 
534
  with gr.Blocks(title="Андрей AI") as demo:
535
- gr.Markdown("# 🤖 Андрей AI (Грамотный + Стриминг + GGUF)\n### Настоящая нейросеть с постокенной генерацией")
536
 
537
  chatbot = gr.Chatbot(height=400, label="Диалог")
538
  msg = gr.Textbox(label="Сообщение", placeholder="Напишите что-нибудь...")
539
 
540
  with gr.Row():
541
  clear = gr.Button("🧹 Очистить историю")
542
- train_btn = gr.Button("🎓 Обучить модель (20 эпох)")
543
 
544
  status = gr.Textbox(label="Статус обучения", interactive=False)
545
 
 
10
  import warnings
11
  import time
12
 
13
+ # Подавляем технические предупреждения
14
  warnings.filterwarnings("ignore", message="The PyTorch API of nested tensors is in prototype stage")
15
  warnings.filterwarnings("ignore", category=UserWarning, module="torch.nn.modules.transformer")
16
 
17
  # ============ НАСТРОЙКИ ============
18
  DATA_DIR = '/data'
19
  os.makedirs(DATA_DIR, exist_ok=True)
20
+ MODEL_BIN = os.path.join(DATA_DIR, 'andrey_final.bin')
21
+ MODEL_GGUF = os.path.join(DATA_DIR, 'andrey_final.gguf')
22
 
23
  # ============ СЛОВАРЬ ============
24
  WORDS = [
25
+ 'привет', 'здравствуй', 'добрый', 'день', 'утро', 'вечер', 'ночь', 'рад', 'видеть',
26
+ 'как', 'ты', 'дела', 'жизнь', 'настроение', 'что', 'нового', 'кто', 'где', 'когда', 'почему',
27
+ 'хорошо', 'отлично', 'нормально', 'плохо', 'спасибо', 'пожалуйста', 'да', 'нет',
 
28
  'я', 'мы', 'он', 'она', 'думаю', 'знаю', 'хочу', 'могу', 'буду', 'люблю', 'работаю', 'учусь',
 
 
29
  'андрей', 'бот', 'помощник', 'нейросеть', 'евгений', 'создатель', 'openrussianai', 'тверь', 'россия',
30
+ 'hugging', 'face', 'платформа', 'дом', 'мир', 'люди', 'друг', 'время', 'сегодня', 'завтра',
 
 
31
  'плюс', 'минус', 'умножить', 'разделить', 'равно', 'ноль', 'один', 'два', 'три', 'четыре', 'пять',
 
32
  'и', 'а', 'но', 'или', 'в', 'на', 'с', 'из', 'к', 'у', 'не', 'ли', 'же', 'бы', 'очень', 'уже', 'ещё',
33
+ 'мой', 'твой', 'наш', 'этот', 'тот', 'какой', 'который', 'весь', 'сам',
34
+ 'расскажи', 'покажи', 'объясни', 'помоги', 'скажи', 'шутка', 'смех', 'радость', 'счастье', 'удача'
 
 
35
  ]
36
 
37
  word_to_idx = {w: i+3 for i, w in enumerate(WORDS)}
 
47
  def tokenize(text):
48
  return [word_to_idx.get(w, UNK) for w in text.lower().split()]
49
 
50
+ # Жесткая фильтрация спецтокенов при выводе
51
  def detokenize(tokens):
52
+ words = []
53
+ for t in tokens:
54
+ t = int(t)
55
+ if t in [PAD, UNK, START]:
56
+ continue
57
+ w = idx_to_word.get(t, '')
58
+ if w and not w.startswith('['):
59
+ words.append(w)
60
+ return ' '.join(words)
61
 
62
  def pad_sequence(seq, max_len=MAX_LEN):
63
  return (seq + [PAD] * max_len)[:max_len]
64
 
65
+ # ============ АРХИТЕКТУРА ============
66
  class PositionalEncoding(nn.Module):
67
  def __init__(self, d_model, dropout=0.1, max_len=5000):
68
  super().__init__()
 
129
  ("здравствуй", "здравствуй рад тебя видеть"),
130
  ("доброе утро", "доброе утро хорошего дня"),
131
  ("добрый день", "добрый день чем могу помочь"),
 
 
132
  ("как дела", "у меня всё хорошо а у тебя"),
133
  ("как ты", "я отлично спасибо что спросил"),
 
 
 
 
134
  ("кто ты", "я андрей искусственный интеллект помощник"),
 
 
 
135
  ("как тебя зовут", "меня зовут андрей"),
 
 
136
  ("где ты живёшь", "я живу на платформе hugging face"),
137
  ("кто тебя создал", "меня создал евгений из openrussianai"),
138
  ("что такое openrussianai", "это компания разработчиков из россии"),
139
  ("ты из россии", "да мой создатель из твери россия"),
140
  ("сколько будет два плюс два", "два плюс два равно четыре"),
 
 
 
141
  ("расскажи шутку", "почему программисты путают хэллоуин и рождество"),
 
142
  ("мне грустно", "не грусти всё будет хорошо я рядом"),
 
 
 
143
  ("спасибо", "пожалуйста обращайся если нужна помощь"),
 
144
  ("пока", "до свидания хорошего настроения"),
 
145
  ("что ты умеешь", "я умею отвечать на вопросы и считать"),
146
  ("ты умный", "я стараюсь учиться каждый день"),
147
  ("мы друзья", "конечно я рад нашей дружбе"),
 
 
148
  ("что такое любовь", "любовь это забота и внимание к другому"),
 
 
 
149
  ("помоги мне", "конечно скажи что именно нужно сделать"),
 
 
 
150
  ("ты спишь", "нет я всегда на связи и готов помочь"),
151
  ("ты ешь", "нет мне не нужна обычная еда"),
 
 
 
 
 
 
 
152
  ("ты мечтаешь", "я мечтаю стать самым полезным помощником"),
 
153
  ("ты злой", "нет я добрый и дружелюбный бот"),
 
 
 
154
  ("ты хороший", "спасибо я стараюсь быть хорошим"),
 
 
155
  ("ты красивый", "спасибо мой код очень элегантен"),
156
  ("ты быстрый", "да я обрабатываю информацию мгновенно"),
 
157
  ("ты сильный", "моя сила в знаниях и алгоритмах"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  ]
159
 
160
  FALLBACK_DICT = {q.lower(): a for q, a in DIALOGUES}
 
190
  print(f"✅ Веса загружены из {self.bin_file}")
191
  return True
192
  except Exception as e:
193
+ print(f"⚠️ Ошибка загрузки: {e}")
194
  return False
195
 
196
  def save_weights(self):
 
198
  state = {
199
  'model_state': self.model.state_dict(),
200
  'vocab_size': vocab_size, 'd_model': 128, 'nhead': 4,
201
+ 'num_layers': 2, 'dim_feedforward': 256,
202
  'word_to_idx': word_to_idx,
203
  'idx_to_word': {str(k): v for k, v in idx_to_word.items()},
204
+ 'memory': self.memory, 'version': '11.0-No-ZeroGPU-Train',
205
  'created': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
206
  }
207
  torch.save(state, self.bin_file)
208
+ print(f"✅ Сохранено .bin: {os.path.getsize(self.bin_file)/1024:.1f} КБ")
 
 
 
 
 
 
209
 
210
+ # ВАЖНО: Убран декоратор @spaces.GPU. Обучение идет мгновенно на CPU/GPU без очереди.
211
+ def train(self, epochs=50):
212
+ print(f"🚀 Обучение ({epochs} эпох) на доступном устройстве...")
213
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  self.model.to(device)
215
  self.model.train()
216
 
 
242
  total_loss += loss.item()
243
  n_batches += 1
244
 
245
+ if epoch % 10 == 0:
246
  print(f"Эпоха {epoch}/{epochs} | Loss: {total_loss/n_batches:.4f}")
247
 
248
  self.memory['epochs_trained'] += epochs
249
  self.model.cpu()
250
  self.save_weights()
251
+ return f"✅ Обучение завершено! Эпох: {self.memory['epochs_trained']}"
252
 
253
  def get_fallback_answer(self, question):
254
  q_clean = question.lower().strip()
255
  if q_clean in FALLBACK_DICT: return FALLBACK_DICT[q_clean]
256
  for q, a in DIALOGUES:
257
  if q in q_clean or q_clean in q: return a
258
+ return "Я пока учусь, но стараюсь понимать тебя."
259
 
260
+ # Генерация оставлена под @spaces.GPU для стабильности в среде Hugging Face
261
+ @spaces.GPU(duration=10)
262
+ def generate_tokens(self, question, history=None, temperature=0.3, max_length=15):
263
  device = torch.device('cuda')
264
  self.model.to(device)
265
  self.model.eval()
266
 
267
  q = question.lower().strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
+ # Подаем на вход ТОЛЬКО текст пользователя, как при обучении
270
+ ctx_tokens = tokenize(q)
271
  if not ctx_tokens:
272
  self.model.cpu()
273
  return [self.get_fallback_answer(q)]
 
276
 
277
  src = torch.tensor([pad_sequence(ctx_tokens, MAX_LEN)], dtype=torch.long).to(device)
278
  response_tokens = []
279
+ last_token = -1
280
 
281
  try:
282
  with torch.no_grad():
 
291
  _, next_token = torch.max(probs, dim=-1)
292
  next_token = next_token.item()
293
 
294
+ # Защита от спецтокенов и зацикливания
295
+ if next_token in [PAD, UNK, START] or next_token == last_token:
296
+ break
297
+
298
+ last_token = next_token
299
  word = idx_to_word.get(next_token, '')
300
+ if word and not word.startswith('['):
301
  response_tokens.append(word)
302
 
303
  decoder_input = torch.cat([decoder_input, torch.tensor([[next_token]], dtype=torch.long).to(device)], dim=1)
 
306
  finally:
307
  self.model.cpu()
308
 
309
+ if not response_tokens:
310
+ return [self.get_fallback_answer(q)]
311
+
312
+ return response_tokens
313
 
314
+ # ============ GRADIO ИНТЕРФЕЙС ============
315
  def gradio_chat(message, history):
316
  if not message:
317
  return "", history or []
 
318
  if history is None:
319
  history = []
320
 
 
321
  history = history + [{"role": "user", "content": message}]
322
  history.append({"role": "assistant", "content": ""})
323
 
 
324
  tokens = andrey.generate_tokens(message, history)
325
 
 
326
  current_text = ""
327
  for token in tokens:
328
  current_text += token + " "
329
  history[-1]["content"] = current_text.strip()
330
  yield "", history
331
+ time.sleep(0.08)
332
 
333
  def start_training():
334
+ return andrey.train(epochs=50)
335
 
336
  with gr.Blocks(title="Андрей AI") as demo:
337
+ gr.Markdown("# 🤖 Андрей AI (Оптимизированный)\n### Обучение без ZeroGPU, мгновенный стриминг")
338
 
339
  chatbot = gr.Chatbot(height=400, label="Диалог")
340
  msg = gr.Textbox(label="Сообщение", placeholder="Напишите что-нибудь...")
341
 
342
  with gr.Row():
343
  clear = gr.Button("🧹 Очистить историю")
344
+ train_btn = gr.Button("🎓 Обучить модель (50 эпох, ~3 сек)")
345
 
346
  status = gr.Textbox(label="Статус обучения", interactive=False)
347