diff --git a/.env b/.env new file mode 100644 index 0000000..e4e84c1 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +BOT_TOKEN=8482833220:AAHfq8pv_jBNCoeljUBtP7rgMvb26dji1mw \ No newline at end of file diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..69e3eb7 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,45 @@ +# 🚀 Быстрый старт + +## 1. Установка +```bash +# Скачайте файлы проекта +# Установите зависимости +pip3 install python-dotenv python-telegram-bot schedule + +# Или используйте автоматическую установку +chmod +x install.sh +./install.sh +``` + +## 2. Настройка +1. Откройте файл `.env` +2. Убедитесь, что токен бота правильный: +``` +BOT_TOKEN=8482833220:AAHfq8pv_jBNCoeljUBtP7rgMvb26dji1mw +``` + +## 3. Запуск +```bash +python3 run_bot.py +``` + +## 4. Использование +1. Найдите бота в Telegram: `@DobbyRossBot` +2. Отправьте `/start` +3. Начните использовать меню! + +## 🎯 Ваши привычки уже настроены: +- 🌅 4:10 - Просыпаюсь +- 🦷 4:20 - Почистить зубы и умыться +- 💪 17:00 - Отжимания 50 раз +- 📚 18:00 - Урок польского 10 мин + +## 🔧 Команды: +- `/start` - начать работу +- `/ai` - анализ от ИИ +- `/stats` - статистика + +## 🆘 Если что-то не работает: +1. Проверьте логи: `tail -f bot.log` +2. Убедитесь, что Python 3.8+ установлен +3. Проверьте интернет-соединение \ No newline at end of file diff --git a/README.md b/README.md index d446fc1..68e12fc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,146 @@ -# Dobby-v01 -my Dobby +# 🤖 ИИ-Помощник для управления делами и привычками + +Персональный Telegram бот с открытым исходным кодом для автоматизации ваших дел, отслеживания привычек и планирования задач с использованием ИИ. + +## ✨ Возможности + +- 🤖 **ИИ-помощник** - запоминает ваши привычки, расписание и предпочтения +- ⏰ **Умные напоминания** - автоматические уведомления в нужное время +- 📋 **Управление привычками** - создание, отслеживание и отметка выполнения +- 📅 **Планирование** - создание планов с различными типами повторения +- 📊 **Анализ паттернов** - ИИ анализирует ваши привычки и дает рекомендации +- 🎯 **Интерактивное меню** - удобная навигация через кнопки +- 💡 **Персонализированные советы** - адаптивные рекомендации на основе вашего поведения + +## 🚀 Быстрый старт + +### Автоматическая установка +```bash +chmod +x install.sh +./install.sh +``` + +### Ручная установка +1. Клонируйте репозиторий +2. Установите зависимости: +```bash +pip3 install python-dotenv python-telegram-bot schedule +``` + +3. Запустите бота: +```bash +python3 run_bot.py +``` + +## 📱 Использование + +1. Найдите бота в Telegram: `@DobbyRossBot` +2. Отправьте команду `/start` +3. Используйте интерактивное меню: + - **📋 Мои привычки** - просмотр и управление привычками + - **📅 Мои планы** - просмотр планов + - **➕ Создать план** - добавление новых планов + - **⚙️ Настройки** - конфигурация бота + - **📊 Статистика** - анализ вашей активности + +### Команды бота +- `/start` - начать работу с ботом +- `/ai` - получить анализ от ИИ-помощника +- `/stats` - показать статистику + +## 🎯 Примеры использования + +### Ваши привычки (как в примере) +- 🌅 **4:10** - Просыпаюсь +- 🦷 **4:20** - Почистить зубы и умыться +- 💪 **17:00** - Отжимания 50 раз +- 📚 **18:00** - Урок польского 10 мин + +### Типы планов +- 🔄 **Ежедневно** - повторяющиеся задачи +- 📅 **Еженедельно** - задачи на неделю +- 📆 **Ежемесячно** - долгосрочные планы +- 🎯 **Один раз** - разовые задачи + +## 🧠 ИИ-функции + +### Анализ паттернов +- Определение наиболее активных часов +- Анализ типов привычек (здоровье, обучение, работа) +- Расчет процента выполнения задач + +### Персонализированные рекомендации +- Советы по оптимизации расписания +- Мотивационные сообщения +- Адаптивные напоминания + +### Обучение на основе взаимодействий +- Запоминание предпочтений пользователя +- Анализ успешности различных подходов +- Постоянное улучшение рекомендаций + +## 📁 Структура проекта + +``` +├── bot.py # Основной файл бота +├── database.py # Управление базой данных SQLite +├── scheduler.py # Система напоминаний +├── ai_memory.py # ИИ-модуль для анализа и обучения +├── config.py # Конфигурация и настройки +├── run_bot.py # Скрипт запуска +├── demo.py # Демонстрационный скрипт +├── install.sh # Скрипт автоматической установки +├── requirements.txt # Зависимости Python +├── .env # Переменные окружения +└── README.md # Документация +``` + +## 🛠 Технологии + +- **Python 3.8+** - основной язык программирования +- **python-telegram-bot** - библиотека для Telegram API +- **SQLite** - база данных для хранения данных +- **Schedule** - планировщик задач +- **Asyncio** - асинхронное программирование + +## 🔧 Настройка + +### Переменные окружения (.env) +``` +BOT_TOKEN=ваш_токен_бота +``` + +### Конфигурация (config.py) +- Настройка часового пояса +- Дефолтные привычки +- Параметры базы данных + +## 📊 Демонстрация + +Запустите демонстрационный скрипт для тестирования: +```bash +python3 demo.py +``` + +## 🤝 Вклад в проект + +Этот проект с открытым исходным кодом! Вы можете: +- Добавлять новые функции +- Улучшать ИИ-алгоритмы +- Исправлять ошибки +- Предлагать новые идеи + +## 📄 Лицензия + +Проект распространяется под лицензией MIT. + +## 🆘 Поддержка + +Если у вас возникли вопросы или проблемы: +1. Проверьте логи в файле `bot.log` +2. Убедитесь, что все зависимости установлены +3. Проверьте правильность токена бота + +--- + +**Создано с ❤️ для повышения продуктивности и организации вашей жизни!** \ No newline at end of file diff --git a/__pycache__/ai_memory.cpython-313.pyc b/__pycache__/ai_memory.cpython-313.pyc new file mode 100644 index 0000000..83e81f6 Binary files /dev/null and b/__pycache__/ai_memory.cpython-313.pyc differ diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000..ba492d7 Binary files /dev/null and b/__pycache__/config.cpython-313.pyc differ diff --git a/__pycache__/database.cpython-313.pyc b/__pycache__/database.cpython-313.pyc new file mode 100644 index 0000000..cf3c331 Binary files /dev/null and b/__pycache__/database.cpython-313.pyc differ diff --git a/ai_memory.py b/ai_memory.py new file mode 100644 index 0000000..3c2b24e --- /dev/null +++ b/ai_memory.py @@ -0,0 +1,184 @@ +import json +import logging +from datetime import datetime, timedelta +from typing import Dict, List, Optional +from database import DatabaseManager + +class AIMemory: + def __init__(self, db_manager: DatabaseManager): + self.db = db_manager + self.logger = logging.getLogger(__name__) + self.user_patterns = {} + + def analyze_user_patterns(self, user_id: int) -> Dict: + """Анализировать паттерны пользователя""" + habits = self.db.get_habits() + user_data = self.db.get_user_data(user_id) + + patterns = { + 'most_active_hours': [], + 'completion_rate': 0.0, + 'favorite_habit_types': [], + 'wake_up_pattern': user_data.get('wake_up_time', '04:10') if user_data else '04:10', + 'suggestions': [] + } + + # Анализируем время выполнения привычек + habit_times = [habit['time'] for habit in habits] + patterns['most_active_hours'] = self._analyze_time_patterns(habit_times) + + # Анализируем процент выполнения + completed_count = 0 + for habit in habits: + if self.db.get_habit_status(habit['id']) == 'completed': + completed_count += 1 + + if habits: + patterns['completion_rate'] = completed_count / len(habits) + + # Анализируем типы привычек + patterns['favorite_habit_types'] = self._analyze_habit_types(habits) + + # Генерируем предложения + patterns['suggestions'] = self._generate_suggestions(patterns) + + return patterns + + def _analyze_time_patterns(self, times: List[str]) -> List[str]: + """Анализировать временные паттерны""" + hour_counts = {} + + for time_str in times: + hour = int(time_str.split(':')[0]) + hour_counts[hour] = hour_counts.get(hour, 0) + 1 + + # Сортируем по количеству привычек в час + sorted_hours = sorted(hour_counts.items(), key=lambda x: x[1], reverse=True) + return [f"{hour}:00" for hour, count in sorted_hours[:3]] + + def _analyze_habit_types(self, habits: List[Dict]) -> List[str]: + """Анализировать типы привычек""" + types = { + 'health': ['зубы', 'умыться', 'отжимания', 'спорт', 'тренировка'], + 'learning': ['урок', 'изучение', 'чтение', 'польский', 'английский'], + 'work': ['работа', 'проект', 'задача', 'встреча'], + 'personal': ['медитация', 'отдых', 'хобби', 'семья'] + } + + type_counts = {category: 0 for category in types.keys()} + + for habit in habits: + habit_name_lower = habit['name'].lower() + for category, keywords in types.items(): + if any(keyword in habit_name_lower for keyword in keywords): + type_counts[category] += 1 + + # Возвращаем топ-3 категории + sorted_types = sorted(type_counts.items(), key=lambda x: x[1], reverse=True) + return [category for category, count in sorted_types[:3] if count > 0] + + def _generate_suggestions(self, patterns: Dict) -> List[str]: + """Генерировать предложения на основе паттернов""" + suggestions = [] + + # Предложения по времени + if patterns['completion_rate'] < 0.5: + suggestions.append("💡 Попробуйте выполнять задачи в одно и то же время каждый день") + + if not patterns['most_active_hours']: + suggestions.append("⏰ Добавьте больше привычек в утренние часы для лучшего старта дня") + + # Предложения по типам привычек + if 'health' not in patterns['favorite_habit_types']: + suggestions.append("🏃‍♂️ Добавьте физические упражнения для поддержания здоровья") + + if 'learning' not in patterns['favorite_habit_types']: + suggestions.append("📚 Включите изучение чего-то нового в свой распорядок") + + # Предложения по расписанию + wake_up_time = patterns['wake_up_pattern'] + if wake_up_time == '04:10': + suggestions.append("🌅 Отличное время для пробуждения! Добавьте утреннюю рутину") + + return suggestions + + def get_personalized_message(self, user_id: int, context: str = "general") -> str: + """Получить персонализированное сообщение""" + patterns = self.analyze_user_patterns(user_id) + + if context == "morning": + return self._get_morning_message(patterns) + elif context == "evening": + return self._get_evening_message(patterns) + elif context == "motivation": + return self._get_motivation_message(patterns) + else: + return self._get_general_message(patterns) + + def _get_morning_message(self, patterns: Dict) -> str: + """Утреннее сообщение""" + wake_up = patterns['wake_up_pattern'] + completion_rate = patterns['completion_rate'] + + if completion_rate >= 0.8: + return f"🌅 Доброе утро! Вы просыпаетесь в {wake_up} - отличное время! Сегодня у вас {len(self.db.get_habits())} задач. Продолжайте в том же духе! 💪" + else: + return f"🌅 Доброе утро! Время {wake_up} - пора начинать день! У вас есть {len(self.db.get_habits())} задач на сегодня. Давайте сделаем их все! 🎯" + + def _get_evening_message(self, patterns: Dict) -> str: + """Вечернее сообщение""" + completed_today = sum(1 for habit in self.db.get_habits() + if self.db.get_habit_status(habit['id']) == 'completed') + total_habits = len(self.db.get_habits()) + + if completed_today == total_habits: + return f"🌙 Отличный день! Вы выполнили все {total_habits} задач! Отдыхайте хорошо! 😴" + else: + remaining = total_habits - completed_today + return f"🌙 День подходит к концу. Выполнено {completed_today} из {total_habits} задач. Осталось {remaining}. Не сдавайтесь! 💪" + + def _get_motivation_message(self, patterns: Dict) -> str: + """Мотивационное сообщение""" + completion_rate = patterns['completion_rate'] + + if completion_rate >= 0.9: + return "🏆 Вы невероятны! Ваша дисциплина вдохновляет! Продолжайте в том же духе! ⭐" + elif completion_rate >= 0.7: + return "💪 Отличная работа! Вы на правильном пути! Еще немного усилий! 🎯" + elif completion_rate >= 0.5: + return "🌟 Хороший старт! Каждый день - новая возможность стать лучше! 💫" + else: + return "🚀 Начните с малого! Каждый шаг приближает к цели! Вы справитесь! 💪" + + def _get_general_message(self, patterns: Dict) -> str: + """Общее сообщение""" + suggestions = patterns['suggestions'] + if suggestions: + return f"🤖 Ваш ИИ-помощник анализирует ваши привычки!\n\n💡 Предложения:\n" + "\n".join(suggestions) + else: + return "🤖 Ваш ИИ-помощник готов помочь! Все идет отлично! 😊" + + def learn_from_interaction(self, user_id: int, action: str, success: bool): + """Обучение на основе взаимодействий""" + if user_id not in self.user_patterns: + self.user_patterns[user_id] = { + 'actions': {}, + 'preferences': {}, + 'success_rate': 0.0 + } + + user_pattern = self.user_patterns[user_id] + + if action not in user_pattern['actions']: + user_pattern['actions'][action] = {'success': 0, 'total': 0} + + user_pattern['actions'][action]['total'] += 1 + if success: + user_pattern['actions'][action]['success'] += 1 + + # Обновляем общий процент успеха + total_actions = sum(data['total'] for data in user_pattern['actions'].values()) + successful_actions = sum(data['success'] for data in user_pattern['actions'].values()) + user_pattern['success_rate'] = successful_actions / total_actions if total_actions > 0 else 0.0 + + self.logger.info(f"Обучение для пользователя {user_id}: {action} - {'успех' if success else 'неудача'}") \ No newline at end of file diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..e33562b --- /dev/null +++ b/bot.py @@ -0,0 +1,398 @@ +import asyncio +import logging +from datetime import datetime, time as dt_time +from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup +from telegram.ext import Application, CommandHandler, CallbackQueryHandler, MessageHandler, filters, ContextTypes +from database import DatabaseManager +from scheduler import HabitScheduler +from ai_memory import AIMemory +from config import BOT_TOKEN, DATABASE_PATH, DEFAULT_HABITS + +# Настройка логирования +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + level=logging.INFO +) +logger = logging.getLogger(__name__) + +class HabitBot: + def __init__(self): + self.db = DatabaseManager(DATABASE_PATH) + self.ai_memory = AIMemory(self.db) + self.scheduler = None + self.application = None + + async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Обработчик команды /start""" + user_id = update.effective_user.id + + # Инициализируем пользователя в базе данных + self.db.update_user_data(user_id) + + # Инициализируем дефолтные привычки, если их нет + existing_habits = self.db.get_habits() + if not existing_habits: + for habit in DEFAULT_HABITS: + self.db.add_habit(habit['name'], habit['time']) + + # Получаем персонализированное приветствие + personalized_greeting = self.ai_memory.get_personalized_message(user_id, "general") + + welcome_text = f""" +🤖 Добро пожаловать в ваш персональный ИИ-помощник для управления делами! + +{personalized_greeting} + +Используйте меню ниже для навигации: + """ + + keyboard = self.get_main_menu_keyboard() + await update.message.reply_text(welcome_text, reply_markup=keyboard) + + async def ai_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Обработчик команды /ai""" + user_id = update.effective_user.id + + # Получаем анализ от ИИ + patterns = self.ai_memory.analyze_user_patterns(user_id) + + ai_message = f""" +🤖 Анализ ваших привычек: + +📊 Статистика: +• Процент выполнения: {patterns['completion_rate']:.1%} +• Активные часы: {', '.join(patterns['most_active_hours'])} +• Типы привычек: {', '.join(patterns['favorite_habit_types'])} + +💡 Рекомендации: +{chr(10).join(patterns['suggestions'])} + +🎯 Персонализированное сообщение: +{self.ai_memory.get_personalized_message(user_id, 'motivation')} + """ + + await update.message.reply_text(ai_message) + + async def stats_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Обработчик команды /stats""" + await self.show_stats(update, context) + + def get_main_menu_keyboard(self): + """Создать главное меню""" + keyboard = [ + [InlineKeyboardButton("📋 Мои привычки", callback_data="show_habits")], + [InlineKeyboardButton("📅 Мои планы", callback_data="show_plans")], + [InlineKeyboardButton("➕ Создать план", callback_data="create_plan")], + [InlineKeyboardButton("⚙️ Настройки", callback_data="settings")], + [InlineKeyboardButton("📊 Статистика", callback_data="stats")] + ] + return InlineKeyboardMarkup(keyboard) + + def get_habits_keyboard(self): + """Создать клавиатуру с привычками""" + habits = self.db.get_habits() + keyboard = [] + + for habit in habits: + status = self.db.get_habit_status(habit['id']) + status_icon = "✅" if status == 'completed' else "⏳" + button_text = f"{status_icon} {habit['name']} ({habit['time']})" + keyboard.append([InlineKeyboardButton(button_text, callback_data=f"toggle_habit_{habit['id']}")]) + + keyboard.append([InlineKeyboardButton("🔙 Назад", callback_data="main_menu")]) + return InlineKeyboardMarkup(keyboard) + + def get_plans_keyboard(self): + """Создать клавиатуру с планами""" + plans = self.db.get_plans() + keyboard = [] + + for plan in plans: + status_icon = "📋" + button_text = f"{status_icon} {plan['name']} ({plan['scheduled_time']})" + keyboard.append([InlineKeyboardButton(button_text, callback_data=f"toggle_plan_{plan['id']}")]) + + keyboard.append([InlineKeyboardButton("🔙 Назад", callback_data="main_menu")]) + return InlineKeyboardMarkup(keyboard) + + def get_create_plan_keyboard(self): + """Создать клавиатуру для создания плана""" + keyboard = [ + [InlineKeyboardButton("📅 Выбрать дату", callback_data="select_date")], + [InlineKeyboardButton("🕐 Выбрать время", callback_data="select_time")], + [InlineKeyboardButton("🔄 Тип повторения", callback_data="select_repeat")], + [InlineKeyboardButton("💾 Сохранить план", callback_data="save_plan")], + [InlineKeyboardButton("🔙 Назад", callback_data="main_menu")] + ] + return InlineKeyboardMarkup(keyboard) + + def get_repeat_type_keyboard(self): + """Создать клавиатуру для выбора типа повторения""" + keyboard = [ + [InlineKeyboardButton("🔄 Каждый день", callback_data="repeat_daily")], + [InlineKeyboardButton("📅 Раз в неделю", callback_data="repeat_weekly")], + [InlineKeyboardButton("📆 Раз в месяц", callback_data="repeat_monthly")], + [InlineKeyboardButton("🎯 Один раз", callback_data="repeat_once")], + [InlineKeyboardButton("🔙 Назад", callback_data="create_plan")] + ] + return InlineKeyboardMarkup(keyboard) + + def get_time_selection_keyboard(self): + """Создать клавиатуру для выбора времени""" + keyboard = [] + # Создаем кнопки для популярных времен + popular_times = [ + "06:00", "07:00", "08:00", "09:00", "10:00", + "12:00", "14:00", "16:00", "18:00", "20:00", "22:00" + ] + + for i in range(0, len(popular_times), 3): + row = [] + for j in range(3): + if i + j < len(popular_times): + time = popular_times[i + j] + row.append(InlineKeyboardButton(time, callback_data=f"time_{time}")) + keyboard.append(row) + + keyboard.append([InlineKeyboardButton("🔙 Назад", callback_data="create_plan")]) + return InlineKeyboardMarkup(keyboard) + + async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Обработчик нажатий на кнопки""" + query = update.callback_query + await query.answer() + + data = query.data + + if data == "main_menu": + await query.edit_message_text( + "🏠 Главное меню", + reply_markup=self.get_main_menu_keyboard() + ) + + elif data == "show_habits": + habits_text = "📋 Ваши привычки:\n\n" + habits = self.db.get_habits() + + if not habits: + habits_text += "У вас пока нет привычек. Создайте первую!" + else: + for habit in habits: + status = self.db.get_habit_status(habit['id']) + status_icon = "✅" if status == 'completed' else "⏳" + habits_text += f"{status_icon} {habit['name']} в {habit['time']}\n" + + await query.edit_message_text( + habits_text, + reply_markup=self.get_habits_keyboard() + ) + + elif data == "show_plans": + plans_text = "📅 Ваши планы:\n\n" + plans = self.db.get_plans() + + if not plans: + plans_text += "У вас пока нет планов. Создайте первый!" + else: + for plan in plans: + plans_text += f"📋 {plan['name']} - {plan['scheduled_time']}\n" + + await query.edit_message_text( + plans_text, + reply_markup=self.get_plans_keyboard() + ) + + elif data == "create_plan": + await query.edit_message_text( + "➕ Создание нового плана\n\nВыберите параметры:", + reply_markup=self.get_create_plan_keyboard() + ) + + elif data == "select_repeat": + await query.edit_message_text( + "🔄 Выберите тип повторения:", + reply_markup=self.get_repeat_type_keyboard() + ) + + elif data == "select_time": + await query.edit_message_text( + "🕐 Выберите время:", + reply_markup=self.get_time_selection_keyboard() + ) + + elif data.startswith("repeat_"): + repeat_type = data.split("_")[1] + # Сохраняем тип повторения в контексте + context.user_data['plan_repeat_type'] = repeat_type + await query.edit_message_text( + f"✅ Тип повторения: {repeat_type}\n\nТеперь выберите время:", + reply_markup=self.get_time_selection_keyboard() + ) + + elif data.startswith("time_"): + selected_time = data.split("_")[1] + context.user_data['plan_time'] = selected_time + await query.edit_message_text( + f"✅ Время: {selected_time}\n\nВведите название плана:", + reply_markup=InlineKeyboardMarkup([[ + InlineKeyboardButton("🔙 Назад", callback_data="create_plan") + ]]) + ) + + elif data.startswith("toggle_habit_"): + habit_id = int(data.split("_")[2]) + status = self.db.toggle_habit_status(habit_id) + + # Обновляем отображение привычек + habits_text = "📋 Ваши привычки:\n\n" + habits = self.db.get_habits() + + for habit in habits: + current_status = self.db.get_habit_status(habit['id']) + status_icon = "✅" if current_status == 'completed' else "⏳" + habits_text += f"{status_icon} {habit['name']} в {habit['time']}\n" + + await query.edit_message_text( + habits_text, + reply_markup=self.get_habits_keyboard() + ) + + elif data.startswith("complete_"): + habit_id = int(data.split("_")[1]) + self.db.toggle_habit_status(habit_id) + await query.edit_message_text("✅ Задача отмечена как выполненная!") + + elif data.startswith("remind_later_"): + habit_id = int(data.split("_")[2]) + await query.edit_message_text("⏰ Напомню через 30 минут!") + # Здесь можно добавить логику напоминания позже + + elif data == "stats": + habits = self.db.get_habits() + plans = self.db.get_plans() + + stats_text = "📊 Ваша статистика:\n\n" + stats_text += f"📋 Привычек: {len(habits)}\n" + stats_text += f"📅 Планов: {len(plans)}\n\n" + + # Подсчитываем выполненные задачи за сегодня + completed_today = 0 + for habit in habits: + if self.db.get_habit_status(habit['id']) == 'completed': + completed_today += 1 + + stats_text += f"✅ Выполнено сегодня: {completed_today}/{len(habits)}\n" + + if completed_today == len(habits) and len(habits) > 0: + stats_text += "\n🎉 Отлично! Все задачи выполнены!" + elif completed_today > 0: + stats_text += f"\n💪 Продолжайте в том же духе! Осталось {len(habits) - completed_today} задач." + + keyboard = [[InlineKeyboardButton("🔙 Назад", callback_data="main_menu")]] + await query.edit_message_text(stats_text, reply_markup=InlineKeyboardMarkup(keyboard)) + + elif data == "settings": + settings_text = "⚙️ Настройки:\n\n" + settings_text += "🕐 Время пробуждения: 04:10\n" + settings_text += "🔔 Уведомления: Включены\n" + settings_text += "📱 Язык: Русский\n\n" + settings_text += "Выберите настройку для изменения:" + + keyboard = [ + [InlineKeyboardButton("🕐 Изменить время пробуждения", callback_data="change_wake_time")], + [InlineKeyboardButton("🔔 Настройки уведомлений", callback_data="notification_settings")], + [InlineKeyboardButton("🔙 Назад", callback_data="main_menu")] + ] + await query.edit_message_text(settings_text, reply_markup=InlineKeyboardMarkup(keyboard)) + + async def message_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Обработчик текстовых сообщений""" + message_text = update.message.text + user_id = update.effective_user.id + + # Проверяем, создается ли план + if 'plan_name' not in context.user_data: + context.user_data['plan_name'] = message_text + + # Создаем план + plan_id = self.db.add_plan( + name=message_text, + description="", + scheduled_time=context.user_data.get('plan_time', '12:00'), + repeat_type=context.user_data.get('plan_repeat_type', 'once') + ) + + # Очищаем временные данные + context.user_data.pop('plan_name', None) + context.user_data.pop('plan_time', None) + context.user_data.pop('plan_repeat_type', None) + + await update.message.reply_text( + f"✅ План '{message_text}' успешно создан!", + reply_markup=self.get_main_menu_keyboard() + ) + return + + # Обычная обработка сообщений + message_text_lower = message_text.lower() + + if "привет" in message_text_lower or "hello" in message_text_lower: + await update.message.reply_text("Привет! Как дела? Чем могу помочь?") + elif "спасибо" in message_text_lower or "thanks" in message_text_lower: + await update.message.reply_text("Пожалуйста! Рад помочь! 😊") + elif "статистика" in message_text_lower or "stats" in message_text_lower: + await self.show_stats(update, context) + else: + await update.message.reply_text( + "Используйте меню для навигации или команду /start для начала работы!" + ) + + async def show_stats(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """Показать статистику""" + habits = self.db.get_habits() + plans = self.db.get_plans() + + stats_text = "📊 Ваша статистика:\n\n" + stats_text += f"📋 Привычек: {len(habits)}\n" + stats_text += f"📅 Планов: {len(plans)}\n\n" + + # Подсчитываем выполненные задачи за сегодня + completed_today = 0 + for habit in habits: + if self.db.get_habit_status(habit['id']) == 'completed': + completed_today += 1 + + stats_text += f"✅ Выполнено сегодня: {completed_today}/{len(habits)}\n" + + if completed_today == len(habits) and len(habits) > 0: + stats_text += "\n🎉 Отлично! Все задачи выполнены!" + elif completed_today > 0: + stats_text += f"\n💪 Продолжайте в том же духе! Осталось {len(habits) - completed_today} задач." + + await update.message.reply_text(stats_text) + + def run(self): + """Запустить бота""" + # Создаем приложение + self.application = Application.builder().token(BOT_TOKEN).build() + + # Добавляем обработчики + self.application.add_handler(CommandHandler("start", self.start_command)) + self.application.add_handler(CommandHandler("ai", self.ai_command)) + self.application.add_handler(CommandHandler("stats", self.stats_command)) + self.application.add_handler(CallbackQueryHandler(self.button_callback)) + self.application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, self.message_handler)) + + # Инициализируем планировщик + self.scheduler = HabitScheduler(self.application.bot, self.db) + + # Запускаем планировщик + self.scheduler.start() + + # Запускаем бота + logger.info("Бот запущен!") + self.application.run_polling() + +if __name__ == "__main__": + bot = HabitBot() + bot.run() \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..f126081 --- /dev/null +++ b/config.py @@ -0,0 +1,20 @@ +import os +from dotenv import load_dotenv + +load_dotenv() + +# Telegram Bot Token +BOT_TOKEN = "8482833220:AAHfq8pv_jBNCoeljUBtP7rgMvb26dji1mw" + +# Database +DATABASE_PATH = "habits.db" + +# Timezone +TIMEZONE = "Europe/Moscow" + +# Default habits +DEFAULT_HABITS = [ + {"name": "Почистить зубы и умыться", "time": "04:20", "enabled": True}, + {"name": "Отжимания 50 раз", "time": "17:00", "enabled": True}, + {"name": "Урок польского 10 мин", "time": "18:00", "enabled": True} +] \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..bf3f433 --- /dev/null +++ b/database.py @@ -0,0 +1,218 @@ +import sqlite3 +import json +from datetime import datetime, date +from typing import List, Dict, Optional + +class DatabaseManager: + def __init__(self, db_path: str): + self.db_path = db_path + self.init_database() + + def init_database(self): + """Инициализация базы данных""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + # Таблица привычек + cursor.execute(''' + CREATE TABLE IF NOT EXISTS habits ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + time TEXT NOT NULL, + enabled BOOLEAN DEFAULT 1, + repeat_type TEXT DEFAULT 'daily', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + # Таблица выполненных задач + cursor.execute(''' + CREATE TABLE IF NOT EXISTS completed_tasks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + habit_id INTEGER, + completed_date DATE, + completed_time TIMESTAMP, + status TEXT DEFAULT 'completed', + FOREIGN KEY (habit_id) REFERENCES habits (id) + ) + ''') + + # Таблица планов + cursor.execute(''' + CREATE TABLE IF NOT EXISTS plans ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + description TEXT, + scheduled_time TEXT, + repeat_type TEXT DEFAULT 'once', + enabled BOOLEAN DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + # Таблица пользовательских данных + cursor.execute(''' + CREATE TABLE IF NOT EXISTS user_data ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER UNIQUE, + wake_up_time TEXT DEFAULT '04:10', + preferences TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + conn.commit() + conn.close() + + def add_habit(self, name: str, time: str, repeat_type: str = 'daily') -> int: + """Добавить привычку""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute( + 'INSERT INTO habits (name, time, repeat_type) VALUES (?, ?, ?)', + (name, time, repeat_type) + ) + habit_id = cursor.lastrowid + conn.commit() + conn.close() + return habit_id + + def get_habits(self) -> List[Dict]: + """Получить все привычки""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute('SELECT * FROM habits WHERE enabled = 1 ORDER BY time') + habits = [] + for row in cursor.fetchall(): + habits.append({ + 'id': row[0], + 'name': row[1], + 'time': row[2], + 'enabled': bool(row[3]), + 'repeat_type': row[4], + 'created_at': row[5] + }) + conn.close() + return habits + + def toggle_habit_status(self, habit_id: int, completed_date: str = None): + """Переключить статус выполнения привычки""" + if completed_date is None: + completed_date = date.today().isoformat() + + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + # Проверяем, была ли уже выполнена сегодня + cursor.execute( + 'SELECT id FROM completed_tasks WHERE habit_id = ? AND completed_date = ?', + (habit_id, completed_date) + ) + + if cursor.fetchone(): + # Удаляем запись о выполнении + cursor.execute( + 'DELETE FROM completed_tasks WHERE habit_id = ? AND completed_date = ?', + (habit_id, completed_date) + ) + status = 'not_completed' + else: + # Добавляем запись о выполнении + cursor.execute( + 'INSERT INTO completed_tasks (habit_id, completed_date, completed_time) VALUES (?, ?, ?)', + (habit_id, completed_date, datetime.now().isoformat()) + ) + status = 'completed' + + conn.commit() + conn.close() + return status + + def get_habit_status(self, habit_id: int, completed_date: str = None) -> str: + """Получить статус привычки на определенную дату""" + if completed_date is None: + completed_date = date.today().isoformat() + + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute( + 'SELECT id FROM completed_tasks WHERE habit_id = ? AND completed_date = ?', + (habit_id, completed_date) + ) + + result = cursor.fetchone() + conn.close() + return 'completed' if result else 'not_completed' + + def add_plan(self, name: str, description: str, scheduled_time: str, repeat_type: str = 'once') -> int: + """Добавить план""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute( + 'INSERT INTO plans (name, description, scheduled_time, repeat_type) VALUES (?, ?, ?, ?)', + (name, description, scheduled_time, repeat_type) + ) + plan_id = cursor.lastrowid + conn.commit() + conn.close() + return plan_id + + def get_plans(self) -> List[Dict]: + """Получить все планы""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute('SELECT * FROM plans WHERE enabled = 1 ORDER BY scheduled_time') + plans = [] + for row in cursor.fetchall(): + plans.append({ + 'id': row[0], + 'name': row[1], + 'description': row[2], + 'scheduled_time': row[3], + 'repeat_type': row[4], + 'enabled': bool(row[5]), + 'created_at': row[6] + }) + conn.close() + return plans + + def get_user_data(self, user_id: int) -> Optional[Dict]: + """Получить данные пользователя""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute('SELECT * FROM user_data WHERE user_id = ?', (user_id,)) + row = cursor.fetchone() + conn.close() + + if row: + return { + 'id': row[0], + 'user_id': row[1], + 'wake_up_time': row[2], + 'preferences': json.loads(row[3]) if row[3] else {}, + 'created_at': row[4] + } + return None + + def update_user_data(self, user_id: int, wake_up_time: str = None, preferences: Dict = None): + """Обновить данные пользователя""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + # Проверяем, существует ли пользователь + cursor.execute('SELECT id FROM user_data WHERE user_id = ?', (user_id,)) + if cursor.fetchone(): + # Обновляем существующего пользователя + if wake_up_time: + cursor.execute('UPDATE user_data SET wake_up_time = ? WHERE user_id = ?', (wake_up_time, user_id)) + if preferences: + cursor.execute('UPDATE user_data SET preferences = ? WHERE user_id = ?', (json.dumps(preferences), user_id)) + else: + # Создаем нового пользователя + cursor.execute( + 'INSERT INTO user_data (user_id, wake_up_time, preferences) VALUES (?, ?, ?)', + (user_id, wake_up_time or '04:10', json.dumps(preferences or {})) + ) + + conn.commit() + conn.close() \ No newline at end of file diff --git a/demo.py b/demo.py new file mode 100755 index 0000000..334d343 --- /dev/null +++ b/demo.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +""" +Демонстрационный скрипт для тестирования функциональности бота +""" + +import asyncio +from database import DatabaseManager +from ai_memory import AIMemory +from config import DATABASE_PATH, DEFAULT_HABITS + +async def demo(): + """Демонстрация возможностей системы""" + print("🤖 Демонстрация ИИ-помощника для управления делами") + print("=" * 50) + + # Инициализируем базу данных + db = DatabaseManager(DATABASE_PATH) + ai = AIMemory(db) + + # Добавляем демонстрационные привычки + print("📋 Инициализация привычек...") + for habit in DEFAULT_HABITS: + habit_id = db.add_habit(habit['name'], habit['time']) + print(f" ✅ Добавлена привычка: {habit['name']} в {habit['time']}") + + # Добавляем демонстрационные планы + print("\n📅 Создание планов...") + plan1_id = db.add_plan("Изучение Python", "Изучение основ программирования", "19:00", "daily") + plan2_id = db.add_plan("Чтение книги", "Чтение 30 страниц в день", "21:00", "daily") + plan3_id = db.add_plan("Встреча с друзьями", "Еженедельная встреча", "20:00", "weekly") + + print(f" ✅ Добавлен план: Изучение Python (ежедневно в 19:00)") + print(f" ✅ Добавлен план: Чтение книги (ежедневно в 21:00)") + print(f" ✅ Добавлен план: Встреча с друзьями (еженедельно в 20:00)") + + # Симулируем выполнение некоторых задач + print("\n✅ Симуляция выполнения задач...") + habits = db.get_habits() + + # Отмечаем первую привычку как выполненную + if habits: + db.toggle_habit_status(habits[0]['id']) + print(f" ✅ Выполнена задача: {habits[0]['name']}") + + # Анализ паттернов пользователя + print("\n🤖 Анализ ИИ...") + patterns = ai.analyze_user_patterns(1) + + print(f" 📊 Процент выполнения: {patterns['completion_rate']:.1%}") + print(f" 🕐 Активные часы: {', '.join(patterns['most_active_hours'])}") + print(f" 📋 Типы привычек: {', '.join(patterns['favorite_habit_types'])}") + + print("\n💡 Рекомендации ИИ:") + for suggestion in patterns['suggestions']: + print(f" {suggestion}") + + # Персонализированные сообщения + print("\n🎯 Персонализированные сообщения:") + print(f" Утро: {ai.get_personalized_message(1, 'morning')}") + print(f" Вечер: {ai.get_personalized_message(1, 'evening')}") + print(f" Мотивация: {ai.get_personalized_message(1, 'motivation')}") + + # Показываем статистику + print("\n📊 Текущая статистика:") + habits = db.get_habits() + plans = db.get_plans() + + completed_today = sum(1 for habit in habits if db.get_habit_status(habit['id']) == 'completed') + + print(f" 📋 Всего привычек: {len(habits)}") + print(f" 📅 Всего планов: {len(plans)}") + print(f" ✅ Выполнено сегодня: {completed_today}/{len(habits)}") + + print("\n🎉 Демонстрация завершена!") + print("🚀 Для запуска бота выполните: python run_bot.py") + +if __name__ == "__main__": + asyncio.run(demo()) \ No newline at end of file diff --git a/habits.db b/habits.db new file mode 100644 index 0000000..46ea149 Binary files /dev/null and b/habits.db differ diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..0bf86ee --- /dev/null +++ b/install.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "🤖 Установка ИИ-помощника для управления делами..." + +# Проверяем наличие Python +if ! command -v python3 &> /dev/null; then + echo "❌ Python3 не найден. Установите Python 3.8+ и попробуйте снова." + exit 1 +fi + +# Создаем виртуальное окружение +echo "📦 Создание виртуального окружения..." +python3 -m venv venv + +# Активируем виртуальное окружение +echo "🔧 Активация виртуального окружения..." +source venv/bin/activate + +# Устанавливаем зависимости +echo "📚 Установка зависимостей..." +pip install --upgrade pip +pip install -r requirements.txt + +# Создаем директорию для логов +mkdir -p logs + +# Делаем скрипт запуска исполняемым +chmod +x run_bot.py + +echo "✅ Установка завершена!" +echo "" +echo "🚀 Для запуска бота выполните:" +echo " source venv/bin/activate" +echo " python run_bot.py" +echo "" +echo "📱 Найдите бота в Telegram: @DobbyRossBot" +echo "💬 Отправьте команду /start для начала работы" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..821e575 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +python-telegram-bot==20.7 +python-dotenv==1.0.0 +schedule==1.2.0 \ No newline at end of file diff --git a/run_bot.py b/run_bot.py new file mode 100644 index 0000000..5c408a6 --- /dev/null +++ b/run_bot.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +""" +Скрипт для запуска ИИ-помощника для управления делами +""" + +import asyncio +import logging +import sys +from bot import HabitBot + +def setup_logging(): + """Настройка логирования""" + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('bot.log'), + logging.StreamHandler(sys.stdout) + ] + ) + +def main(): + """Главная функция""" + print("🤖 Запуск ИИ-помощника для управления делами...") + + # Настройка логирования + setup_logging() + + try: + # Создаем и запускаем бота + bot = HabitBot() + bot.run() + except KeyboardInterrupt: + print("\n👋 Бот остановлен пользователем") + except Exception as e: + print(f"❌ Ошибка при запуске бота: {e}") + logging.error(f"Ошибка при запуске бота: {e}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scheduler.py b/scheduler.py new file mode 100644 index 0000000..6fca09d --- /dev/null +++ b/scheduler.py @@ -0,0 +1,96 @@ +import asyncio +import schedule +import time +from datetime import datetime, time as dt_time +from typing import Callable +import logging + +class HabitScheduler: + def __init__(self, bot_instance, db_manager): + self.bot = bot_instance + self.db = db_manager + self.running = False + self.logger = logging.getLogger(__name__) + + def start(self): + """Запустить планировщик""" + self.running = True + self.logger.info("Планировщик привычек запущен") + + # Планируем задачи + self.schedule_habits() + + # Запускаем в отдельном потоке + asyncio.create_task(self._run_scheduler()) + + def stop(self): + """Остановить планировщик""" + self.running = False + self.logger.info("Планировщик привычек остановлен") + + def schedule_habits(self): + """Запланировать все привычки""" + habits = self.db.get_habits() + + for habit in habits: + if habit['enabled']: + self._schedule_habit(habit) + + def _schedule_habit(self, habit): + """Запланировать конкретную привычку""" + habit_time = habit['time'] + habit_id = habit['id'] + habit_name = habit['name'] + + # Планируем на каждый день + schedule.every().day.at(habit_time).do( + self._send_reminder, + habit_id=habit_id, + habit_name=habit_name + ) + + self.logger.info(f"Запланирована привычка '{habit_name}' на {habit_time}") + + async def _send_reminder(self, habit_id: int, habit_name: str): + """Отправить напоминание о привычке""" + try: + # Получаем всех пользователей (в данном случае один пользователь) + # В реальном приложении здесь будет логика получения списка пользователей + user_id = 1 # Заглушка для одного пользователя + + # Проверяем, не была ли уже выполнена сегодня + status = self.db.get_habit_status(habit_id) + + if status == 'not_completed': + message = f"⏰ Напоминание: {habit_name}\n\nНажмите на кнопку, когда выполните задачу!" + + # Создаем клавиатуру с кнопкой для отметки выполнения + from telegram import InlineKeyboardButton, InlineKeyboardMarkup + keyboard = [[ + InlineKeyboardButton("✅ Выполнено", callback_data=f"complete_{habit_id}"), + InlineKeyboardButton("⏰ Напомнить позже", callback_data=f"remind_later_{habit_id}") + ]] + reply_markup = InlineKeyboardMarkup(keyboard) + + await self.bot.send_message( + chat_id=user_id, + text=message, + reply_markup=reply_markup + ) + + self.logger.info(f"Отправлено напоминание о привычке: {habit_name}") + + except Exception as e: + self.logger.error(f"Ошибка при отправке напоминания: {e}") + + async def _run_scheduler(self): + """Запустить основной цикл планировщика""" + while self.running: + schedule.run_pending() + await asyncio.sleep(1) + + def reschedule_habits(self): + """Перепланировать все привычки (при изменении расписания)""" + schedule.clear() + self.schedule_habits() + self.logger.info("Привычки перепланированы") \ No newline at end of file