| | import numpy as np |
| | import pandas as pd |
| | import requests |
| | from io import StringIO |
| | from sklearn.feature_extraction.text import TfidfVectorizer |
| | from sklearn.metrics.pairwise import cosine_similarity |
| | import speech_recognition as sr |
| | import pyttsx3 |
| | from googlesearch import search |
| | from bs4 import BeautifulSoup |
| | import urllib.request |
| | from urllib.parse import quote |
| |
|
| | class HybridChatBot: |
| | def __init__(self, dataset_url=None): |
| | self.dataset_url = dataset_url |
| | self.qa_pairs = {} |
| | self.vectorizer = TfidfVectorizer() |
| | self.X = None |
| | self.recognizer = sr.Recognizer() |
| | self.engine = pyttsx3.init() |
| | |
| | |
| | voices = self.engine.getProperty('voices') |
| | self.engine.setProperty('voice', voices[0].id) |
| | self.engine.setProperty('rate', 150) |
| | |
| | if dataset_url: |
| | self.load_dataset() |
| | self.train() |
| |
|
| | def load_dataset(self): |
| | """Загрузка датасета с веб-ресурса""" |
| | try: |
| | response = requests.get(self.dataset_url) |
| | response.raise_for_status() |
| | |
| | if self.dataset_url.endswith('.csv'): |
| | data = pd.read_csv(StringIO(response.text)) |
| | elif self.dataset_url.endswith('.json'): |
| | data = pd.read_json(StringIO(response.text)) |
| | else: |
| | print("Формат файла не поддерживается") |
| | return |
| | |
| | for _, row in data.iterrows(): |
| | self.qa_pairs[row["question"].lower()] = row["answer"] |
| | |
| | print(f"Загружено {len(self.qa_pairs)} пар вопрос-ответ") |
| | |
| | except Exception as e: |
| | print(f"Ошибка загрузки датасета: {e}") |
| |
|
| | def train(self): |
| | """Обучение модели на загруженных данных""" |
| | if not self.qa_pairs: |
| | print("Нет данных для обучения!") |
| | return |
| | |
| | questions = list(self.qa_pairs.keys()) |
| | self.X = self.vectorizer.fit_transform(questions) |
| | print("Модель обучена на загруженных данных") |
| |
|
| | def add_qa_pair(self, question, answer): |
| | """Добавление новой пары вопрос-ответ""" |
| | self.qa_pairs[question.lower()] = answer |
| | self.train() |
| |
|
| | def web_search(self, query, num_results=3): |
| | """Выполнение веб-поиска и извлечение информации""" |
| | try: |
| | print(f"\nВыполняю поиск в интернете: {query}") |
| | search_results = [] |
| | |
| | |
| | for url in search(query, num_results=num_results, lang='ru'): |
| | try: |
| | |
| | req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) |
| | with urllib.request.urlopen(req, timeout=5) as response: |
| | html = response.read() |
| | |
| | |
| | soup = BeautifulSoup(html, 'html.parser') |
| | |
| | |
| | for script in soup(["script", "style", "iframe", "nav", "footer"]): |
| | script.extract() |
| | |
| | |
| | text = soup.get_text(separator=' ', strip=True) |
| | text = ' '.join(text.split()[:200]) |
| | |
| | search_results.append({ |
| | 'url': url, |
| | 'content': text |
| | }) |
| | |
| | except Exception as e: |
| | print(f"Ошибка при обработке {url}: {e}") |
| | continue |
| | |
| | return search_results |
| | |
| | except Exception as e: |
| | print(f"Ошибка при выполнении поиска: {e}") |
| | return None |
| |
|
| | def get_response(self, user_input): |
| | """Получение ответа на ввод пользователя""" |
| | if not self.qa_pairs: |
| | return "Я еще не обучен. Пожалуйста, добавьте вопросы и ответы." |
| | |
| | |
| | if "найди в интернете" in user_input.lower() or "найди в интернете" in user_input.lower(): |
| | query = user_input.replace("найди в интернете", "").replace("найди в интернете", "").strip() |
| | search_results = self.web_search(query) |
| | if search_results: |
| | response = "Вот что я нашел в интернете:\n" |
| | for i, result in enumerate(search_results, 1): |
| | response += f"\n{i}. {result['content']}\n(Источник: {result['url']})\n" |
| | return response[:2000] |
| | else: |
| | return "Не удалось найти информацию в интернете." |
| | |
| | |
| | user_vec = self.vectorizer.transform([user_input.lower()]) |
| | similarities = cosine_similarity(user_vec, self.X) |
| | best_match_idx = np.argmax(similarities) |
| | best_match_score = similarities[0, best_match_idx] |
| | |
| | if best_match_score > 0.5: |
| | best_question = list(self.qa_pairs.keys())[best_match_idx] |
| | return self.qa_pairs[best_question] |
| | else: |
| | return "Я не знаю ответ на этот вопрос. Хотите, чтобы я поискал в интернете? (Скажите 'найди в интернете...')" |
| |
|
| | def text_to_speech(self, text): |
| | """Озвучивание текста""" |
| | self.engine.say(text) |
| | self.engine.runAndWait() |
| |
|
| | def speech_to_text(self): |
| | """Распознавание голоса с микрофона""" |
| | with sr.Microphone() as source: |
| | print("\nГоворите сейчас...") |
| | self.recognizer.adjust_for_ambient_noise(source) |
| | try: |
| | audio = self.recognizer.listen(source, timeout=5) |
| | text = self.recognizer.recognize_google(audio, language="ru-RU") |
| | print(f"Распознано: {text}") |
| | return text |
| | except sr.UnknownValueError: |
| | print("Речь не распознана") |
| | return None |
| | except sr.RequestError: |
| | print("Ошибка сервиса распознавания") |
| | return None |
| | except sr.WaitTimeoutError: |
| | print("Время ожидания истекло") |
| | return None |
| |
|
| | def run(self): |
| | """Улучшенный интерфейс взаимодействия""" |
| | print("\n" + "="*50) |
| | print("ДОБРО ПОЖАЛОВАТЬ В ИНТЕЛЛЕКТУАЛЬНЫЙ ЧАТ-БОТ".center(50)) |
| | print("="*50) |
| | |
| | current_mode = "текст" |
| | while True: |
| | print("\n" + "-"*50) |
| | print(f"Текущий режим ввода: {current_mode.upper()}") |
| | print("[1] Отправить текстовое сообщение") |
| | print("[2] Говорить с ботом голосом") |
| | print("[3] Переключить режим ввода") |
| | print("[4] Обучить бота новому ответу") |
| | print("[5] Поиск в интернете") |
| | print("[6] Выход") |
| | |
| | try: |
| | choice = input("Выберите действие (1-6): ").strip() |
| | |
| | if choice == "1": |
| | user_input = input("\nВаше сообщение: ") |
| | if user_input.lower() in ["выход", "стоп"]: |
| | break |
| | |
| | response = self.get_response(user_input) |
| | if response: |
| | print(f"\nБот: {response}") |
| | self.text_to_speech(response) |
| | else: |
| | print("\nБот: Я не знаю что ответить. Хотите научить меня?") |
| | |
| | elif choice == "2": |
| | user_input = self.speech_to_text() |
| | if user_input: |
| | if user_input.lower() in ["выход", "стоп"]: |
| | break |
| | |
| | response = self.get_response(user_input) |
| | if response: |
| | print(f"\nБот: {response}") |
| | self.text_to_speech(response) |
| | else: |
| | print("\nБот: Я не знаю что ответить на это.") |
| | self.text_to_speech("Я не знаю что ответить на это") |
| | |
| | elif choice == "3": |
| | current_mode = "голос" if current_mode == "текст" else "текст" |
| | print(f"\nРежим изменен на: {current_mode.upper()}") |
| | |
| | elif choice == "4": |
| | print("\nОбучение бота:") |
| | question = input("Введите вопрос: ") |
| | answer = input("Введите ответ: ") |
| | self.add_qa_pair(question, answer) |
| | print("Бот успешно обучен!") |
| | |
| | elif choice == "5": |
| | query = input("\nВведите запрос для поиска в интернете: ") |
| | search_results = self.web_search(query) |
| | if search_results: |
| | print("\nРезультаты поиска:") |
| | for i, result in enumerate(search_results, 1): |
| | print(f"\n{i}. {result['content']}\n(Источник: {result['url']})\n") |
| | else: |
| | print("\nНичего не найдено.") |
| | |
| | elif choice == "6": |
| | print("\nЗавершение работы...") |
| | break |
| | |
| | else: |
| | print("\nПожалуйста, выберите вариант от 1 до 6") |
| | |
| | except KeyboardInterrupt: |
| | print("\nЗавершение работы...") |
| | break |
| |
|
| | if __name__ == "__main__": |
| | |
| | DATASET_URL = "https://raw.githubusercontent.com/user/repo/main/qa_data.csv" |
| | |
| | bot = HybridChatBot(DATASET_URL) |
| | bot.run() |