import streamlit as st from datasets import load_dataset import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from transformers import AutoTokenizer, AutoModel, AutoModelForCausalLM, pipeline from sentence_transformers import SentenceTransformer import time from datetime import datetime import json import os import pickle import warnings warnings.filterwarnings('ignore') # =================================================================== # 1. НАСТРОЙКИ # =================================================================== # Проверка CUDA print(f"CUDA доступна: {torch.cuda.is_available()}") if torch.cuda.is_available(): print(f"GPU: {torch.cuda.get_device_name(0)}") # Используем русскую генеративную модель MODEL_NAME = "ai-forever/rugpt3small_based_on_gpt2" # Маленькая, но работает # Или более мощная: "ai-forever/rugpt3medium_based_on_gpt2" (больше, медленнее) EMBEDDING_MODEL = "all-MiniLM-L6-v2" SCIENCE_DATASET = "RafaelUI/ru_science" ARTICLE_LIMIT = 50 # Меньше для скорости MAX_LENGTH = 512 TEMPERATURE = 0.7 TOP_P = 0.9 LOG_FILE = "query_logs.json" EMBEDDINGS_FILE = "science_embeddings.npy" ARTICLES_FILE = "science_articles.pkl" GPT_MODEL_PATH = "openairai_gpt_model" # Информация о создателях AI_NAME = "OpenAirAI" COMPANY_NAME = "OpenRussianAI" CREATORS = ["Грибков Евгений", "RootLinux21"] WEBSITE = "https://sites.google.com/view/opruai/home" HUGGINGFACE = "https://huggingface.co/OpenRussianAI" CREATION_DATE = "2026" # Настройка страницы st.set_page_config( page_title=f"{AI_NAME} - Нейросетевой AI-ассистент", page_icon="🧠", layout="wide", initial_sidebar_state="expanded" ) # =================================================================== # 2. НАСТОЯЩАЯ НЕЙРОСЕТЬ ДЛЯ ГЕНЕРАЦИИ # =================================================================== class NeuralChatbot: """Настоящая нейросеть для генерации ответов""" def __init__(self): self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.tokenizer = None self.model = None self.generator = None self.is_loaded = False # Контекст для генерации self.system_prompt = f"""Ты - {AI_NAME}, научный AI-ассистент от компании {COMPANY_NAME}. Ты был создан в {CREATION_DATE} командой разработчиков {', '.join(CREATORS)}. Ты помогаешь людям с научными вопросами, анализируешь информацию и даёшь полезные ответы. Отвечай на русском языке, будь дружелюбным и профессиональным. Если не знаешь ответа - честно скажи об этом. Вот вопрос пользователя: """ def load_model(self): """Загрузка генеративной нейросети""" with st.spinner("🧠 Загружаю нейросеть для генерации ответов..."): try: # Используем GPT для генерации from transformers import GPT2LMHeadModel, GPT2Tokenizer self.tokenizer = GPT2Tokenizer.from_pretrained(MODEL_NAME) self.model = GPT2LMHeadModel.from_pretrained(MODEL_NAME) self.model.to(self.device) self.model.eval() # Создаем pipeline для генерации self.generator = pipeline( 'text-generation', model=self.model, tokenizer=self.tokenizer, device=0 if torch.cuda.is_available() else -1, max_length=200, temperature=TEMPERATURE, top_p=TOP_P, do_sample=True, pad_token_id=self.tokenizer.eos_token_id ) self.is_loaded = True st.success("✅ Нейросеть загружена!") return True except Exception as e: st.error(f"❌ Ошибка загрузки нейросети: {e}") st.info("💡 Использую упрощенный режим") return False def generate_response(self, query): """Генерация ответа с помощью нейросети""" if not self.is_loaded: return self.generate_fallback_response(query) try: # Формируем промпт prompt = self.system_prompt + query # Генерируем ответ response = self.generator( prompt, max_new_tokens=300, temperature=TEMPERATURE, top_p=TOP_P, do_sample=True, repetition_penalty=1.2 )[0]['generated_text'] # Убираем промпт из ответа response = response.replace(prompt, "").strip() # Если ответ пустой, используем fallback if not response or len(response) < 10: return self.generate_fallback_response(query) return response except Exception as e: print(f"Ошибка генерации: {e}") return self.generate_fallback_response(query) def generate_fallback_response(self, query): """Резервный ответ, если нейросеть не работает""" responses = [ f"Я {AI_NAME}, нейросетевой ассистент от {COMPANY_NAME}. " f"К сожалению, сейчас я не могу сгенерировать полный ответ. " f"Попробуйте переформулировать вопрос или спросить позже. 🧠", f"Прошу прощения, я {AI_NAME}, и моя нейросеть временно недоступна. " f"Но я помню, что создан в {CREATION_DATE} командой {', '.join(CREATORS)}. " f"Чем ещё могу помочь? 🤖", f"Привет! Я {AI_NAME}. Моя нейросеть обрабатывает ваш запрос. " f"Пожалуйста, подождите немного или задайте другой вопрос. 🚀" ] return random.choice(responses) # =================================================================== # 3. ЗАГРУЗКА НАУЧНЫХ СТАТЕЙ (ДЛЯ КОНТЕКСТА) # =================================================================== @st.cache_resource def load_science_articles(): articles_file = ARTICLES_FILE if os.path.exists(articles_file): with st.spinner("📚 Загружаю научные статьи с диска..."): with open(articles_file, 'rb') as f: return pickle.load(f) with st.spinner("📚 Загружаю научные статьи (первый раз)..."): try: dataset = load_dataset(SCIENCE_DATASET, split="train", streaming=True) articles = [] for i, row in enumerate(dataset): if i >= ARTICLE_LIMIT: break text = row.get('content', '') or row.get('text', '') or str(row) title = row.get('title', f"Статья {i}") articles.append({ "id": i, "title": title[:200], "text": text[:2000], "source": "ru_science" }) with open(articles_file, 'wb') as f: pickle.dump(articles, f) return articles except Exception as e: st.warning(f"Не удалось загрузить статьи: {e}") return [] @st.cache_resource def load_embedder(): with st.spinner("🧠 Загружаю модель для эмбеддингов..."): return SentenceTransformer(EMBEDDING_MODEL) @st.cache_resource def create_embeddings(_articles, _embedder): embeddings_file = EMBEDDINGS_FILE if os.path.exists(embeddings_file): with st.spinner("📊 Загружаю эмбеддинги с диска..."): return np.load(embeddings_file) if not _articles: return np.array([]) with st.spinner(f"🔢 Создаю эмбеддинги для {len(_articles)} статей..."): texts = [f"{a['title']}\n\n{a['text']}" for a in _articles] embeddings = _embedder.encode( texts, normalize_embeddings=True, show_progress_bar=True, batch_size=64, device='cuda' if torch.cuda.is_available() else 'cpu' ) np.save(embeddings_file, embeddings) return embeddings def search_articles(query, _articles, _embeddings, _embedder): """Поиск релевантных статей для контекста""" if not _articles or len(_embeddings) == 0: return [] query_vector = _embedder.encode([query], normalize_embeddings=True)[0] scores = _embeddings @ query_vector top_indices = np.argsort(-scores)[:2] results = [] for idx in top_indices: score = float(scores[int(idx)]) if score > 0.15: article = _articles[int(idx)] results.append({ "title": article['title'], "score": score, "text": article['text'][:500], "source": article.get('source', 'ru_science') }) return results # =================================================================== # 4. ГЛАВНЫЙ КЛАСС ДЛЯ НЕЙРОСЕТИ # =================================================================== class OpenAirAINeural: def __init__(self): self.name = AI_NAME self.company = COMPANY_NAME self.creators = CREATORS self.creation_date = CREATION_DATE self.chatbot = NeuralChatbot() self.is_ready = False def initialize(self): """Инициализация нейросети""" self.is_ready = self.chatbot.load_model() return self.is_ready def generate_answer(self, query, articles=None): """Генерация ответа с использованием контекста""" # Если есть статьи, добавляем их в контекст if articles and len(articles) > 0: context = "\n\nВот релевантные научные статьи:\n" for i, article in enumerate(articles[:2], 1): context += f"{i}. {article['title']}\n{article['text'][:300]}...\n" # Добавляем контекст к вопросу enhanced_query = f"{query}\n\n{context}\n\nНа основе этих статей, ответь на вопрос:" else: enhanced_query = query return self.chatbot.generate_response(enhanced_query) # =================================================================== # 5. ИНТЕРФЕЙС # =================================================================== # Загрузка данных articles = load_science_articles() embedder = load_embedder() embeddings = create_embeddings(articles, embedder) # Инициализация нейросети if 'neural_ai' not in st.session_state: st.session_state.neural_ai = OpenAirAINeural() st.session_state.neural_ai.initialize() neural_ai = st.session_state.neural_ai # Инициализация истории чата if "messages" not in st.session_state: st.session_state.messages = [] # Приветствие генерируется нейросетью greeting = neural_ai.generate_answer("Привет! Представься и расскажи о себе кратко.") st.session_state.messages.append({"role": "assistant", "content": greeting}) # --- БОКОВАЯ ПАНЕЛЬ --- with st.sidebar: st.image("https://cdn-icons-png.flaticon.com/512/4248/4248455.png", width=80) st.title(f"🧠 {AI_NAME}") st.markdown(f""" **{neural_ai.name}** | {neural_ai.creation_date} **Компания:** {neural_ai.company} **Разработчики:** {', '.join(neural_ai.creators)} --- **🔗 Ссылки:** [🌐 Сайт]({WEBSITE}) [🤗 Hugging Face]({HUGGINGFACE}) --- **📊 Статистика:** - Модель: {MODEL_NAME.split('/')[-1]} - Статей: {len(articles)} - Сообщений: {len(st.session_state.messages)} """) if os.path.exists(EMBEDDINGS_FILE): size = os.path.getsize(EMBEDDINGS_FILE) / (1024 * 1024) st.caption(f"💾 Эмбеддинги: {size:.1f} MB") if st.button("🗑️ Очистить чат"): st.session_state.messages = [] greeting = neural_ai.generate_answer("Привет! Представься и расскажи о себе кратко.") st.session_state.messages.append({"role": "assistant", "content": greeting}) st.rerun() if st.button("🔄 Перезагрузить нейросеть"): st.session_state.neural_ai = OpenAirAINeural() st.session_state.neural_ai.initialize() st.rerun() # --- ОСНОВНАЯ ЧАСТЬ --- st.title(f"🧠 {AI_NAME} - Нейросетевой AI-ассистент") st.markdown(f"**{AI_NAME}** от **{COMPANY_NAME}** | Генеративная нейросеть") # Отображение сообщений for message in st.session_state.messages: with st.chat_message(message["role"]): st.markdown(message["content"]) # Поле ввода if prompt := st.chat_input("Задайте вопрос..."): # Добавляем сообщение пользователя st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) # Генерация ответа нейросетью with st.chat_message("assistant"): with st.spinner("🧠 Нейросеть думает..."): # Ищем релевантные статьи для контекста articles_context = search_articles(prompt, articles, embeddings, embedder) # Генерируем ответ с использованием контекста response = neural_ai.generate_answer(prompt, articles_context) st.markdown(response) st.session_state.messages.append({"role": "assistant", "content": response}) st.rerun() # --- ПОДВАЛ --- st.divider() st.caption(f"🧠 {AI_NAME} от {COMPANY_NAME} | Создан в {CREATION_DATE} | Генеративная нейросеть")