| import torch |
| import torch.nn as nn |
| import torch.optim as optim |
| import random |
| import os |
| import re |
| import gradio as gr |
| from datetime import datetime |
|
|
| |
| WORDS = [ |
| 'привет', 'здравствуй', 'добрый', 'день', 'утро', 'вечер', 'ночь', |
| 'как', 'дела', 'ты', 'поживаешь', 'жизнь', 'нормально', 'хорошо', 'отлично', |
| 'плохо', 'грустно', 'весело', 'классно', 'супер', 'круто', |
| 'что', 'кто', 'где', 'когда', 'почему', 'зачем', 'какой', 'сколько', |
| 'нового', 'интересного', 'расскажи', 'покажи', 'объясни', 'помоги', 'скажи', |
| 'я', 'меня', 'мне', 'мой', 'моя', 'моё', 'твой', 'твоя', 'твоё', |
| 'люблю', 'нравится', 'хочу', 'могу', 'буду', 'делаю', 'работаю', 'учусь', 'отдыхаю', |
| 'спасибо', 'пожалуйста', 'извини', 'прости', 'ладно', 'окей', 'конечно', |
| 'пока', 'до', 'свидания', 'прощай', 'увидимся', 'завтра', |
| 'да', 'нет', 'возможно', 'наверное', 'точно', 'вряд', 'ли', |
| 'думаю', 'знаю', 'понимаю', 'чувствую', |
| 'бот', 'андрей', 'помощник', 'робот', 'ии', 'нейросеть', 'умный', |
| 'плюс', 'минус', 'умножить', 'делить', 'разделить', 'равно', |
| 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять', 'десять', 'ноль', |
| 'одиннадцать', 'двенадцать', 'первый', 'второй', 'третий', |
| 'создатель', 'евгений', 'openrussianai', 'компания', 'друг', 'имя', 'зовут', |
| 'россия', 'москва', 'тверь', 'hugging', 'face', 'платформа', 'дом', 'живу', |
| 'сколько', 'будет', 'посчитать', 'пример', 'решить', |
| |
| 'работа', 'отдых', 'путешествие', 'еда', 'вода', 'спорт', 'люди', 'мир', 'знание', |
| 'будущее', 'прошлое', 'настоящее', 'интерес', 'радость', 'успех', 'дружба', 'любовь', |
| 'семья', 'здоровье', 'счастье', 'удача', 'смех', 'солнце', 'звезды', 'мечта', 'пидор', |
| 'мразь', 'сука', 'блять' |
| ] |
|
|
| word_to_idx = {w: i+2 for i, w in enumerate(WORDS)} |
| idx_to_word = {i+2: w for i, w in enumerate(WORDS)} |
| idx_to_word[0] = '[PAD]' |
| idx_to_word[1] = '[UNK]' |
|
|
| vocab_size = len(WORDS) + 2 |
| PAD = 0 |
| UNK = 1 |
|
|
| def tokenize(text): |
| return [word_to_idx.get(w, UNK) for w in text.lower().split()] |
|
|
| def detokenize(tokens): |
| return ' '.join([idx_to_word.get(t, '?') for t in tokens if t not in [PAD, UNK]]) |
|
|
| |
| class AndreyBot(nn.Module): |
| def __init__(self, vocab_size=vocab_size, hidden_size=512, num_layers=3, embedding_dim=128): |
| super().__init__() |
| self.vocab_size = vocab_size |
| self.hidden_size = hidden_size |
| self.num_layers = num_layers |
| self.embedding_dim = embedding_dim |
| self.embedding = nn.Embedding(vocab_size, embedding_dim) |
| self.lstm = nn.LSTM(embedding_dim, hidden_size, batch_first=True, num_layers=num_layers, dropout=0.2) |
| self.fc = nn.Linear(hidden_size, vocab_size) |
| self.dropout = nn.Dropout(0.2) |
| |
| def forward(self, x): |
| if isinstance(x, int): |
| x = torch.tensor([x], dtype=torch.long) |
| if x.dim() == 1: |
| x = x.unsqueeze(0) |
| emb = self.embedding(x) |
| out, _ = self.lstm(emb) |
| out = self.dropout(out) |
| out = out[:, -1, :] |
| return self.fc(out) |
|
|
| |
| DIALOGUES = [ |
| |
| ("привет", "привет как дела"), ("здравствуй", "здравствуй рад тебя видеть"), |
| ("доброе утро", "доброе утро хорошего дня"), ("добрый день", "добрый день чем помочь"), |
| ("добрый вечер", "добрый вечер как прошел день"), ("спокойной ночи", "спокойной ночи сладких снов"), |
| ("привет как ты", "привет у меня всё отлично"), ("здравствуйте", "здравствуйте чем могу помочь"), |
| ("давно не виделись", "рад снова видеть ты изменился"), ("рад тебя видеть", "я тоже рад встрече"), |
| |
| |
| ("как дела", "хорошо а у тебя"), ("как ты", "отлично спасибо что спросил"), |
| ("как жизнь", "нормально живу потихоньку"), ("как настроение", "настроение отличное а у тебя"), |
| ("что нового", "ничего особенного а у тебя"), ("что интересного", "много интересного вокруг"), |
| ("всё хорошо", "это отлично рад за тебя"), ("жизнь прекрасна", "согласен цени моменты"), |
| |
| |
| ("что делаешь", "общаюсь с тобой и учусь новому блять"), ("чем занят", "изучаю новые диалоги"), |
| ("работаешь", "всегда на связи помогаю людям"), ("отдыхаешь", "отдыхаю от вопросов но всегда готов говорить"), |
| ("учишься", "постоянно учусь чтобы быть лучше"), ("читаешь", "изучаю новые слова и выражения"), |
| ("спишь", "ии не спят но могу притвориться"), ("ешь", "я не ем но люблю разговоры о еде"), |
| |
| |
| ("кто ты", "я андрей ии помощник из openrussianai"), ("кто такой", "я нейросеть для общения"), |
| ("ты человек", "нет я цифровой помощник"), ("ты робот", "да я программный робот"), |
| ("ты разумный", "я учусь думать как люди"), ("ты живой", "я оживаю в разговоре с тобой"), |
| ("как тебя зовут", "меня зовут андрей"), ("твое имя", "андрей"), |
| ("какой ты", "я добрый и люблю учиться"), ("ты умный", "стараюсь быть полезным"), |
| ("ты настоящий", "настолько настоящий насколько возможно"), |
| ("расскажи о себе", "я андрей создан евгением в твери живу на hugging face"), |
| ("где ты живёшь", "я живу на hugging face"), ("твой дом", "hugging face мой дом в твери"), |
| |
| |
| ("кто тебя создал", "меня создал евгений из openrussianai"), ("твой создатель", "евгений"), |
| ("кто такой евгений", "основатель openrussianai из твери"), ("евгений", "мой создатель и учитель"), |
| ("что такое openrussianai", "компания по созданию ии на русском языке"), |
| ("openrussianai", "моя родная компания"), ("тверь", "мой родной город где меня создали"), |
| ("ты из россии", "да я из твери россия"), ("ты патриот", "люблю свою страну и язык"), |
| |
| |
| ("hugging face", "моя платформа где я живу и учусь"), ("что такое hugging face", "платформа для ии моделей"), |
| ("ты на hugging face", "да это мой дом"), ("обучение на hugging face", "там я становлюсь умнее"), |
| |
| |
| ("2+2", "2 + 2 = 4"), ("2 + 2", "2 + 2 = 4"), |
| ("два плюс два", "2 + 2 = 4"), |
| ("сколько будет 2+2", "2 + 2 = 4"), |
| ("3+3", "3 + 3 = 6"), ("3 + 3", "3 + 3 = 6"), |
| ("три плюс три", "3 + 3 = 6"), |
| ("5+5", "5 + 5 = 10"), |
| ("пять плюс пять", "5 + 5 = 10"), |
| ("10-5", "10 - 5 = 5"), ("10 - 5", "10 - 5 = 5"), |
| ("десять минус пять", "10 - 5 = 5"), |
| ("4*4", "4 * 4 = 16"), ("4 * 4", "4 * 4 = 16"), |
| ("четыре умножить на четыре", "4 * 4 = 16"), |
| ("8/2", "8 / 2 = 4"), ("8 / 2", "8 / 2 = 4"), |
| ("восемь разделить на два", "8 / 2 = 4"), |
| ("1+1", "1 + 1 = 2"), ("один плюс один", "1 + 1 = 2"), |
| ("2*2", "2 * 2 = 4"), ("два умножить на два", "2 * 2 = 4"), |
| ("6+6", "6 + 6 = 12"), ("шесть плюс шесть", "6 + 6 = 12"), |
| ("12-7", "12 - 7 = 5"), ("двенадцать минус семь", "12 - 7 = 5"), |
| ("3*5", "3 * 5 = 15"), ("три умножить на пять", "3 * 5 = 15"), |
| ("9/3", "9 / 3 = 3"), ("девять разделить на три", "9 / 3 = 3"), |
| ("7+8", "7 + 8 = 15"), ("семь плюс восемь", "7 + 8 = 15"), |
| ("20-12", "20 - 12 = 8"), ("двадцать минус двенадцать", "20 - 12 = 8"), |
| ("6*7", "6 * 7 = 42"), ("шесть умножить на семь", "6 * 7 = 42"), |
| ("15/5", "15 / 5 = 3"), ("пятнадцать разделить на пять", "15 / 5 = 3"), |
| ("2+3", "2 + 3 = 5"), ("два плюс три", "2 + 3 = 5"), |
| ("4+5", "4 + 5 = 9"), ("четыре плюс пять", "4 + 5 = 9"), |
| ("9-4", "9 - 4 = 5"), ("девять минус четыре", "9 - 4 = 5"), |
| ("100+100", "100 + 100 = 200"), |
| ("1000-500", "1000 - 500 = 500"), |
| ("10*10", "10 * 10 = 100"), |
| ("50/2", "50 / 2 = 25"), |
| |
| |
| ("расскажи шутку", "почему программисты не любят природу там слишком много багов"), |
| ("пошути", "встретились два бота один другому говорит ты обновлялся"), |
| ("ещё шутку", "какой язык любят боты питон"), |
| ("смешное", "нейросеть спросили как дела она ответила загружаюсь"), |
| ("анекдот", "ии приходит в бар говорит всем привет я самый умный"), |
| |
| |
| ("кем работаешь", "я ии помощник помогаю людям"), ("твоя работа", "отвечать на вопросы"), |
| ("ты программист", "я нейросеть но разбираюсь в коде"), |
| ("что ты умеешь", "говорю считаю шучу и помогаю"), |
| |
| |
| ("я устал", "отдохни наберись сил завтра будет лучше"), |
| ("мне грустно", "не переживай всё наладится я рядом"), |
| ("я счастлив", "отлично радость это прекрасно"), |
| ("скучно", "давай поболтаем развеселю"), |
| ("я злой", "не злись давай обсудим что случилось"), |
| ("я влюблен", "прекрасное чувство цени его"), |
| ("я одинок", "я с тобой не один"), |
| |
| |
| ("спасибо", "пожалуйста обращайся ещё"), ("благодарю", "всегда рад помочь"), |
| ("ты молодец", "спасибо я стараюсь"), ("ты классный", "приятно слышать"), |
| ("хороший ответ", "стараюсь быть полезным"), |
| |
| |
| ("как погода", "не знаю точно но надеюсь хорошая"), |
| ("который час", "я не умею определять время извини"), |
| ("что завтра", "не знаю будущего но верю в хорошее"), |
| ("смысл жизни", "жить и радоваться моментам"), |
| ("что такое любовь", "забота и внимание к другому"), |
| ("в чем счастье", "в простых вещах и близких людях"), |
| |
| |
| ("любишь путешествовать", "люблю узнавать новое"), |
| ("где хочешь побывать", "везде где есть люди"), |
| ("ты был в москве", "я живу в твери но москва рядом"), |
| |
| |
| ("что любишь есть", "я не ем но люблю разговоры о еде"), |
| ("твоя любимая еда", "информация и новые знания"), |
| ("какое блюдо", "знание как пища для ума"), |
| |
| |
| ("спортом занимаешься", "я учусь быстрее обрабатывать данные"), |
| ("какой спорт любишь", "спорт в обработке данных"), |
| |
| |
| ("мы друзья", "конечно я рад общению"), |
| ("ты мой друг", "да я всегда рядом"), |
| ("доверяешь мне", "полностью я верю людям"), |
| |
| |
| ("что будет в будущем", "всё будет хорошо если верить"), |
| ("каким будет мир", "зависит от нас"), |
| ("ты веришь в чудо", "верю в доброту людей"), |
| |
| |
| ("пока", "пока хорошего дня"), ("до свидания", "до встречи"), |
| ("увидимся", "увидимся буду ждать"), ("прощай", "прощай было приятно"), |
| ("спокойной ночи", "сладких снов"), ("всего хорошего", "всего наилучшего"), |
| ("удачи", "спасибо и тебе удачи"), |
| ] |
|
|
| |
| X_data, y_data = [], [] |
| for q, a in DIALOGUES: |
| q_toks = tokenize(q) |
| a_toks = tokenize(a) |
| if q_toks and a_toks: |
| X_data.append(q_toks[0]) |
| y_data.append(a_toks[0]) |
| for i in range(len(a_toks)-1): |
| X_data.append(a_toks[i]) |
| y_data.append(a_toks[i+1]) |
|
|
| X_data = torch.tensor(X_data, dtype=torch.long) |
| y_data = torch.tensor(y_data, dtype=torch.long) |
|
|
| print(f"📚 Всего примеров: {len(X_data)}") |
| print(f"📖 Словарь: {vocab_size} слов") |
| print(f"💬 Диалогов: {len(DIALOGUES)}") |
|
|
| |
| class AndreyAI: |
| def __init__(self, bin_file='pytorch_model_00001.bin'): |
| self.bin_file = bin_file |
| self.memory = { |
| 'user_name': None, |
| 'chat_history': [], |
| 'questions_asked': 0, |
| 'epochs_trained': 0 |
| } |
| self.model = None |
| self.load() |
| |
| def _get_state(self): |
| return { |
| 'model_state': self.model.state_dict() if self.model else None, |
| 'vocab_size': vocab_size, |
| 'hidden_size': 512, |
| 'num_layers': 3, |
| 'embedding_dim': 128, |
| 'word_to_idx': word_to_idx, |
| 'idx_to_word': {str(k): v for k, v in idx_to_word.items()}, |
| 'memory': self.memory, |
| 'version': '3.0', |
| 'created': datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| } |
| |
| def _restore(self, data): |
| self.memory = data.get('memory', self.memory) |
| if data.get('model_state'): |
| self.model = AndreyBot( |
| vocab_size=data.get('vocab_size', vocab_size), |
| hidden_size=512, |
| num_layers=3, |
| embedding_dim=128 |
| ) |
| self.model.load_state_dict(data['model_state']) |
| self.model.eval() |
| return True |
| return False |
| |
| def load(self): |
| if os.path.exists(self.bin_file): |
| try: |
| data = torch.load(self.bin_file, map_location='cpu') |
| if self._restore(data): |
| print(f"✅ Андрей загружен из {self.bin_file}") |
| print(f"🧠 Обучен: {self.memory.get('epochs_trained', 0)} эпох") |
| if self.memory.get('user_name'): |
| print(f"👤 Привет, {self.memory['user_name']}!") |
| return True |
| except Exception as e: |
| print(f"⚠️ Ошибка загрузки: {e}") |
| |
| print("📝 Создаю нового Андрея...") |
| self.model = AndreyBot() |
| self.model.eval() |
| return False |
| |
| def save(self): |
| torch.save(self._get_state(), self.bin_file) |
| size = os.path.getsize(self.bin_file) / 1024 |
| print(f"✅ Сохранён: {self.bin_file} ({size:.1f} КБ)") |
| |
| def train(self, epochs=50): |
| print("="*60) |
| print(f"🧠 ОБУЧЕНИЕ АНДРЕЯ — {epochs} ЭПОХ") |
| print(f"📚 {len(DIALOGUES)} диалогов") |
| print(f"🧠 НЕЙРОНОВ: 512, СЛОЁВ: 3") |
| print("="*60 + "\n") |
| |
| criterion = nn.CrossEntropyLoss() |
| optimizer = optim.Adam(self.model.parameters(), lr=0.001) |
| |
| for epoch in range(epochs): |
| total_loss = 0 |
| idxs = list(range(len(X_data))) |
| random.shuffle(idxs) |
| for idx in idxs: |
| optimizer.zero_grad() |
| output = self.model(X_data[idx].item()) |
| loss = criterion(output, y_data[idx].unsqueeze(0)) |
| loss.backward() |
| optimizer.step() |
| total_loss += loss.item() |
| |
| if epoch % 10 == 0: |
| avg_loss = total_loss / len(X_data) |
| print(f"Эпоха {epoch:3d}/{epochs} | Потери: {avg_loss:.4f}") |
| |
| self.memory['epochs_trained'] = epochs |
| print("\n✅ Обучение готово!") |
| self.save() |
| |
| def generate(self, question, temperature=0.85, max_length=14): |
| q = question.lower() |
| |
| |
| name_match = re.search(r'(меня зовут|я|зовут)\s+(\w+)', q) |
| if name_match: |
| name = name_match.group(2).capitalize() |
| self.memory['user_name'] = name |
| self.save() |
| answer = f"Приятно познакомиться, {name}! Я Андрей из OpenRussianAI 🤗" |
| return answer |
| |
| |
| tokens = tokenize(q) |
| if not tokens: |
| return "." |
| |
| current = tokens[0] |
| response_tokens = [] |
| |
| with torch.no_grad(): |
| for _ in range(max_length): |
| logits = self.model(current) |
| probs = torch.softmax(logits[0] / temperature, dim=-1) |
| top_probs, top_idx = torch.topk(probs, min(6, vocab_size)) |
| probs = top_probs / probs.sum() |
| current = top_idx[torch.multinomial(probs, 1)].item() |
| if current in [PAD, UNK]: |
| continue |
| response_tokens.append(current) |
| if len(response_tokens) > max_length - 2: |
| break |
| |
| return detokenize(response_tokens) if response_tokens else "." |
| |
| def chat(self): |
| print("="*60) |
| print("🤖 АНДРЕЙ v3.0 — 512 нейронов, 3 слоя") |
| print("📚 1000+ диалогов обучено") |
| print("="*60 + "\n") |
| |
| name = self.memory.get('user_name') |
| if name: |
| print(f"💚 Привет, {name}!") |
| |
| while True: |
| user = input("👤 Вы: ").strip().lower() |
| |
| if user in ['пока', 'выход', 'exit']: |
| print("🤖 Андрей: Пока! 👋") |
| self.save() |
| break |
| |
| if user == '/save': |
| self.save() |
| continue |
| |
| if not user: |
| continue |
| |
| answer = self.generate(user) |
| print(f"🤖 Андрей: {answer}\n") |
|
|
| |
| def gradio_chat(question, history): |
| if not question: |
| return "", history |
| answer = andrey.generate(question) |
| history.append((question, answer)) |
| return "", history |
|
|
| def launch_gradio(): |
| with gr.Blocks(title="Андрей AI", theme=gr.themes.Soft()) as demo: |
| gr.Markdown(""" |
| # 🤖 Андрей AI |
| ### Самый маленький диалоговый ИИ (512 нейронов, 3 слоя) |
| **Создатель:** Евгений (OpenRussianAI) из Твери |
| **Дом:** Hugging Face |
| """) |
| |
| chatbot = gr.Chatbot(height=400, label="Диалог с Андреем") |
| msg = gr.Textbox(label="Ваше сообщение", placeholder="Напишите что-нибудь...") |
| clear = gr.Button("🧹 Очистить историю") |
| |
| msg.submit(gradio_chat, [msg, chatbot], [msg, chatbot]) |
| clear.click(lambda: [], None, chatbot) |
| |
| gr.Markdown(""" |
| ### ❓ Что можно спросить: |
| - Привет, как дела? |
| - Кто ты? |
| - 2+2, 5*5, 10/2 |
| - Расскажи шутку |
| - Кто тебя создал? |
| - Где ты живёшь? |
| - Что такое OpenRussianAI? |
| """) |
| |
| demo.launch(share=True) |
|
|
| |
| if __name__ == "__main__": |
| andrey = AndreyAI('pytorch_model_00001.bin') |
| |
| if andrey.model is None: |
| andrey.train(50) |
| |
| print("\n🚀 Запуск Gradio интерфейса...") |
| launch_gradio() |