mirror of
https://github.com/EDeev/chatping_abobot.git
synced 2026-06-15 19:10:58 +03:00
Compare commits
9 commits
TelegramBo
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c6a250a33 | |||
| b73df23108 | |||
| 616d7295da | |||
| faab8abc8e | |||
| 8f43acaa50 | |||
|
|
de5a86a133 | ||
|
|
ba5aa85800 | ||
|
|
59af13e95b | ||
|
|
178df95ab2 |
10 changed files with 773 additions and 438 deletions
156
README.md
156
README.md
|
|
@ -1,7 +1,153 @@
|
||||||
<h2>Telegram 🤖 ABOBOT / Телеграм 🤖 АБОБОТ</h2>
|
# 🤖 ABOBOT - Telegram Group Management Bot
|
||||||
|
|
||||||
Этот бот создан для чатов в Телеграм , он может упомянуть всех участников в чате, выдать статистику
|

|
||||||
по группе / участнику группы, также имеет ситуативные функции, как: перевод транслита, разворачинание / переворачивание
|

|
||||||
слов, по команде создание опроса и отметка лайк / дизлайк на сообщение учатника группы!
|

|
||||||
|

|
||||||
|
|
||||||
<b>Также вы можете ознакомиться с этим ботом прямо сейчас перейдя по этой <a href="https://t.me/abobusik_bot">ссылке</a></b>
|
Многофункциональный Telegram-бот для управления групповыми чатами с расширенной аналитикой и интерактивными возможностями.
|
||||||
|
|
||||||
|
## 🎯 Основные возможности
|
||||||
|
|
||||||
|
### 📊 Система аналитики
|
||||||
|
- **Комплексная статистика** - детальный учёт активности участников
|
||||||
|
- **Временная сегментация** - анализ данных за месяц и весь период
|
||||||
|
- **Многомерные метрики** - сообщения, ответы, команды, медиафайлы, голосовые
|
||||||
|
|
||||||
|
### 👥 Управление участниками
|
||||||
|
- **Интеллектуальные упоминания** - автоматическое обнаружение имён в сообщениях
|
||||||
|
- **Динамическое именование** - морфологическая обработка и нормализация
|
||||||
|
- **Групповые вызовы** - команда `/all` для оповещения всех участников
|
||||||
|
|
||||||
|
### 🔧 Утилиты и инструменты
|
||||||
|
- **Транслитерация** - автоматический перевод с латиницы на кириллицу
|
||||||
|
- **Транскрипция** - конвертация голосовых сообщений в текст (gTTS)
|
||||||
|
- **Текстовые трансформации** - реверс слов и предложений
|
||||||
|
- **Генерация голоса** - озвучивание текстовых сообщений
|
||||||
|
|
||||||
|
### 🎮 Интерактивные функции
|
||||||
|
- **Игровые механики** - симуляция драк и взаимодействий
|
||||||
|
- **Рандомизация** - генерация случайных чисел в диапазоне
|
||||||
|
- **Советник** - интеграция с API для получения рандомных советов
|
||||||
|
|
||||||
|
## 🏗️ Архитектура системы
|
||||||
|
|
||||||
|
### Технологический стек
|
||||||
|
```
|
||||||
|
Backend Framework: aiogram (Async Telegram Bot API)
|
||||||
|
Database Engine: SQLite (многотабличная структура)
|
||||||
|
NLP Processing: pymorphy3 (морфологический анализ)
|
||||||
|
Speech Recognition: speech_recognition + gTTS
|
||||||
|
Async Framework: asyncio (асинхронная обработка)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Структура базы данных
|
||||||
|
```
|
||||||
|
📁 Databases
|
||||||
|
├── base.db # Основная статистика групп
|
||||||
|
├── users.db # Маппинг пользователей
|
||||||
|
├── groups.db # Индивидуальная статистика участников
|
||||||
|
└── month.db # Временная сегментация данных
|
||||||
|
```
|
||||||
|
|
||||||
|
### Модульная организация
|
||||||
|
```
|
||||||
|
📁 Project Structure
|
||||||
|
├── bot.py # Точка входа и инициализация
|
||||||
|
├── handlers.py # Обработчики событий и команд
|
||||||
|
├── script.py # Бизнес-логика и алгоритмы
|
||||||
|
├── sql.py # Абстракция базы данных
|
||||||
|
├── init.py # Конфигурация и зависимости
|
||||||
|
└── base.py # Константы и настройки
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Быстрый старт
|
||||||
|
|
||||||
|
### Установка зависимостей
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Конфигурация
|
||||||
|
1. Получите токен бота у [@BotFather](https://t.me/BotFather)
|
||||||
|
2. Обновите `TOKEN` в `code/base.py`
|
||||||
|
3. Настройте права администратора для автоудаления системных сообщений
|
||||||
|
|
||||||
|
### Запуск
|
||||||
|
```bash
|
||||||
|
cd code
|
||||||
|
python bot.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 Команды
|
||||||
|
|
||||||
|
| Команда | Функционал |
|
||||||
|
|---------|------------|
|
||||||
|
| `/start`, `/help` | Интерактивное меню с описанием возможностей |
|
||||||
|
| `/all` | Упоминание всех участников группы |
|
||||||
|
| `/stat_group` | Детальная аналитика группы |
|
||||||
|
| `/stat_user` | Персональная статистика пользователя |
|
||||||
|
| `/recognize` | Транскрипция голосового сообщения |
|
||||||
|
| `/edit <имя>` | Установка кастомного имени для упоминаний |
|
||||||
|
| `/back_edit` | Возврат к динамическому именованию |
|
||||||
|
| `/start_bot` | Активация текстовых событий |
|
||||||
|
| `/stop_bot` | Деактивация текстовых событий |
|
||||||
|
|
||||||
|
## 🎲 Текстовые события
|
||||||
|
|
||||||
|
### Интерактивные команды
|
||||||
|
- **"Чмокнуть [имя]"** - позитивное взаимодействие
|
||||||
|
- **"Отмудохать [имя]"** - игровая агрессия
|
||||||
|
- **"Подраться с [имя]"** - симуляция боя с рандомным исходом
|
||||||
|
- **"Число от X до Y"** - генерация случайного числа
|
||||||
|
- **"Переведи (символ) - текст"** - трансформация в "кирпичный" язык
|
||||||
|
- **"Переверни - текст"** - реверс слов с сохранением пунктуации
|
||||||
|
- **"Озвучь - текст"** - генерация голосового сообщения
|
||||||
|
|
||||||
|
## 🔍 Технические особенности
|
||||||
|
|
||||||
|
### Алгоритмы обработки
|
||||||
|
- **Морфологический анализ** - приведение имён к начальной форме
|
||||||
|
- **Детекция транслита** - эвристический алгоритм определения раскладки
|
||||||
|
- **Парсинг голоса** - интеграция Google Speech Recognition
|
||||||
|
- **Обработка пунктуации** - сохранение форматирования при трансформациях
|
||||||
|
|
||||||
|
### Оптимизации производительности
|
||||||
|
- **Асинхронная архитектура** - неблокирующая обработка запросов
|
||||||
|
- **Кэширование соединений** - переиспользование подключений к БД
|
||||||
|
- **Ленивая загрузка** - подгрузка данных по требованию
|
||||||
|
|
||||||
|
## 📈 Метрики и аналитика
|
||||||
|
|
||||||
|
Система ведёт учёт следующих параметров:
|
||||||
|
- Общее количество сообщений
|
||||||
|
- Количество ответов на сообщения
|
||||||
|
- Использование команд бота
|
||||||
|
- Отправка медиафайлов и стикеров
|
||||||
|
- Голосовые сообщения и видеокружки
|
||||||
|
- Размещение ссылок
|
||||||
|
|
||||||
|
## 🛠️ Требования к системе
|
||||||
|
|
||||||
|
- Python 3.8+
|
||||||
|
- Операционная система: Linux/Windows/macOS
|
||||||
|
- RAM: минимум 512MB
|
||||||
|
- Свободное место: 100MB для логов и медиафайлов
|
||||||
|
|
||||||
|
## 📄 Лицензия
|
||||||
|
|
||||||
|
Проект распространяется под лицензией MIT.
|
||||||
|
|
||||||
|
## 👨💻 Автор
|
||||||
|
|
||||||
|
**Деев Егор Викторович** - Backend Developer
|
||||||
|
- GitHub: [@EDeev](https://github.com/EDeev)
|
||||||
|
- Email: egor@deev.space
|
||||||
|
- Telegram: [@Egor_Deev](https://t.me/Egor_Deev)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<sub>⭐ Если проект оказался полезным, поставьте звезду на GitHub!</sub>
|
||||||
|
<p><sub>Создано с ❤️ от вашего дорогого - deev.space ©</sub></p>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# ДАННЫЕ БОТА
|
# ДАННЫЕ БОТА
|
||||||
TOKEN = "" # @chat_abobot
|
TOKEN = "XXXXXXXXXX" # @chat_abobot
|
||||||
DEBAG = "-*********" # Технический чат
|
DEBAG = "XXXXXXXXXX" # Технический чат
|
||||||
|
|
||||||
TEX_GROUP = "-*********"
|
TEX_GROUP = "XXXXXXXXXX"
|
||||||
|
|
||||||
# ОБРАЩЕНИЯ К ПОЛЬЗОВАТЕЛЯМ
|
# ОБРАЩЕНИЯ К ПОЛЬЗОВАТЕЛЯМ
|
||||||
KILL_LIST = ["побить", "отмудохать", "избить", "уебать", "отметелить"]
|
KILL_LIST = ["побить", "отмудохать", "избить", "уебать", "отметелить"]
|
||||||
|
|
|
||||||
442
code/bot.py
442
code/bot.py
|
|
@ -1,422 +1,20 @@
|
||||||
import logging, random, pymorphy2, requests
|
import asyncio
|
||||||
import asyncio, base, re, os, enchant, sql
|
import logging
|
||||||
|
|
||||||
from gtts import gTTS
|
from init import bot, dp
|
||||||
from script import checker, translator, notice, lang_form, revers, upd_stat
|
from handlers import router
|
||||||
from aiogram import Bot, Dispatcher, executor, types
|
|
||||||
from datetime import datetime as dt
|
|
||||||
# from filters import Admin
|
async def main() -> None:
|
||||||
|
dp.include_router(router)
|
||||||
# log level
|
await bot.delete_webhook(drop_pending_updates=True)
|
||||||
logging.basicConfig(level=logging.INFO)
|
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types(), skip_updates=True)
|
||||||
|
|
||||||
# bot init
|
|
||||||
bot = Bot(token=base.TOKEN)
|
if __name__ == '__main__':
|
||||||
dp = Dispatcher(bot)
|
logging.basicConfig(level=logging.INFO)
|
||||||
morph = pymorphy2.MorphAnalyzer()
|
|
||||||
engl_dict = enchant.Dict("en_US")
|
try: asyncio.run(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
# инициализируем соединение с БД
|
print("Бот остановлен")
|
||||||
db = sql.Base('../db/base.db')
|
pass
|
||||||
du = sql.User('../db/users.db')
|
|
||||||
dg = sql.Group('../db/groups.db')
|
|
||||||
dm = sql.Month('../db/month.db')
|
|
||||||
|
|
||||||
# инициализируем фильтры
|
|
||||||
# dp.filters_factory.bind(Admin)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(content_types=["new_chat_members"])
|
|
||||||
async def notification(message: types.Message):
|
|
||||||
if not du.group_exists(message.chat.id):
|
|
||||||
du.add_group(message.chat.id)
|
|
||||||
|
|
||||||
group_id = du.get_group_id(message.chat.id)
|
|
||||||
db.add_group(group_id)
|
|
||||||
dg.created_group(group_id)
|
|
||||||
|
|
||||||
await bot.send_message(message.chat.id, f'<b>Привет группа {message.chat.title}!</b>\n\nВсе функции вы можете '
|
|
||||||
f'узнать по команде /help! Для того, чтобы '
|
|
||||||
f'уведомления по имени и команда /all нормально функционировали, '
|
|
||||||
f'необходимо чтобы каждый участник группы написал хотя бы одно '
|
|
||||||
f'сообщение в чат! Также для того, чтобы системные сообщения удалялись '
|
|
||||||
f'автоматически, необходимо боту выдать права администратора!',
|
|
||||||
types.ParseMode.HTML)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
await message.delete()
|
|
||||||
except Exception:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ
|
|
||||||
@dp.message_handler(content_types=['migrate_to_chat_id', 'migrate_from_chat_id'])
|
|
||||||
async def chat_reload(message: types.Message):
|
|
||||||
if du.group_exists(message.migrate_from_chat_id):
|
|
||||||
du.update_group_id(du.get_group_id(message.migrate_from_chat_id), message.migrate_to_chat_id)
|
|
||||||
|
|
||||||
|
|
||||||
# КОМАНДЫ
|
|
||||||
@dp.message_handler(commands=['start', 'help'])
|
|
||||||
async def helps(message: types.Message):
|
|
||||||
if message.chat.id > 0:
|
|
||||||
user_id = message.from_user.id
|
|
||||||
if not du.user_exists(user_id):
|
|
||||||
du.add_user(user_id)
|
|
||||||
else:
|
|
||||||
group_id, user_id = message.chat.id, message.from_user.id
|
|
||||||
if not du.user_exists(user_id):
|
|
||||||
du.add_user(user_id)
|
|
||||||
if not du.group_exists(group_id):
|
|
||||||
du.add_group(group_id)
|
|
||||||
upd_stat(user_id, group_id, 3, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
|
|
||||||
types.InlineKeyboardButton(text="ИВЕНТЫ", callback_data="even"),
|
|
||||||
types.InlineKeyboardButton(text="АВТОР", callback_data="auth"),
|
|
||||||
types.InlineKeyboardButton(text="ФУНКЦИИ", callback_data="fun")]
|
|
||||||
|
|
||||||
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
|
||||||
keyboard.add(*buttons)
|
|
||||||
|
|
||||||
try:
|
|
||||||
await bot.send_voice(chat_id=message.chat.id, voice=open('../data/tts.ogg', 'rb'),
|
|
||||||
caption='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, '
|
|
||||||
'ивентами и удобными функциями, которые облегчают использование чата)\n\n'
|
|
||||||
'*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на '
|
|
||||||
'команду /report)', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
|
|
||||||
except Exception:
|
|
||||||
await bot.send_message(chat_id=message.chat.id,
|
|
||||||
text='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, '
|
|
||||||
'ивентами и удобными функциями, которые облегчают использование чата)\n\n'
|
|
||||||
'*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на '
|
|
||||||
'команду /report)', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
|
|
||||||
|
|
||||||
|
|
||||||
# ИЛАЙН КЛАВИАТУРА HELP
|
|
||||||
@dp.callback_query_handler(text="auth")
|
|
||||||
async def author(call: types.CallbackQuery):
|
|
||||||
await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот, как бы это не печально звучало, но одна из лучших'
|
|
||||||
' моих работ и если кого-нибудь у меня получится действительно достойный продукт,'
|
|
||||||
' вы сможете о нём узнать в моём телеграм канале *@itsproger*', parse_mode=types.ParseMode.MARKDOWN)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.callback_query_handler(text="fun")
|
|
||||||
async def function(call: types.CallbackQuery):
|
|
||||||
await call.message.answer(text='*| ФУНКЦИИ |*\n\n*1.* Возможность перевода случайно написанного текста на '
|
|
||||||
'транслите\n*2.* Ведение обширной статистики сообщений\n*3.* Упоминание участника '
|
|
||||||
'при написании его имени в чате\n*4.* Автоматическое удаление системных сообщений',
|
|
||||||
parse_mode=types.ParseMode.MARKDOWN)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.callback_query_handler(text="com")
|
|
||||||
async def commands(call: types.CallbackQuery):
|
|
||||||
await call.message.answer(text='<b>| КОМАНДЫ |</b>\n\n/all - упомянуть всех в чате\n/help - полный список функций\n'
|
|
||||||
'/stat_group - полная статистика группы\n/stat_user - полная статистика '
|
|
||||||
'отправителя\n/edit и /back_edit - первая команда даёт возможность '
|
|
||||||
'сменить имя для упоминаний на любое слово, а вторая для возврата динамического '
|
|
||||||
'имени\n/start_bot и /stop_bot - возможность отключения текстовых ивентов',
|
|
||||||
parse_mode=types.ParseMode.HTML)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.callback_query_handler(text="even")
|
|
||||||
async def events(call: types.CallbackQuery):
|
|
||||||
await call.message.answer(text='*| ИВЕНТЫ |*\n\n*"Чмокнуть"* - сделать кому-нибудь приятно\n*"Отмудохать"* - '
|
|
||||||
'выместить злость на кого-нибудь\n*"Число от ... до ..."* - случайное значение из '
|
|
||||||
'диапозона\n*"Подраться с ..."* - повод кого-нибудь побить\n*"Переведи (..) - ..."* '
|
|
||||||
'- перевод слова на керпичный язык\n*"Дай блять совет!"* - даёт рандомный охуенный '
|
|
||||||
'совет\n*"Переверни - ..."* - переворачивает слова в предложении\n*"Озвучь - ..."* '
|
|
||||||
'- озвучивает написанный текст',
|
|
||||||
parse_mode=types.ParseMode.MARKDOWN)
|
|
||||||
|
|
||||||
|
|
||||||
# ОСТАЛЬНЫЕ КОМАНДЫ
|
|
||||||
@dp.message_handler(commands=['all'], commands_prefix='@/')
|
|
||||||
async def every(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
try:
|
|
||||||
await message.reply(notice(du.get_user_id(message.from_user.id), True, du.get_group_id(message.chat.id), message.from_user.id),
|
|
||||||
types.ParseMode.HTML)
|
|
||||||
except Exception as e:
|
|
||||||
# print(repr(e))
|
|
||||||
await message.reply('В группе состоит менее 3х человек, из-за чего команда не работает!')
|
|
||||||
else:
|
|
||||||
await message.reply('Эта команда предназначена для вызова в чате!')
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['stat_group'])
|
|
||||||
async def stat_group(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
group_id = du.get_group_id(message.chat.id)
|
|
||||||
|
|
||||||
group = db.stat_group(group_id)
|
|
||||||
month = db.month_stat_group(group_id)
|
|
||||||
|
|
||||||
await message.answer(text=f'*| СТАТИСТИКА ГРУППЫ |*\n\n'
|
|
||||||
f'*>>* В целом сообщений *[ {message.message_id} ]*\n\n'
|
|
||||||
f'*- За всё время* / *За месяц -*\n'
|
|
||||||
f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n'
|
|
||||||
f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n'
|
|
||||||
f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n'
|
|
||||||
f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n'
|
|
||||||
f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n'
|
|
||||||
f'*>* Медиа файлов *- [ {group[4]} / {month[4] } ]*\n'
|
|
||||||
f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*',
|
|
||||||
parse_mode=types.ParseMode.MARKDOWN)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['stat_user'])
|
|
||||||
async def stat_user(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
|
||||||
|
|
||||||
group = dg.stat_user(user_id, group_id)
|
|
||||||
month = dm.stat_user(user_id, group_id)
|
|
||||||
|
|
||||||
namer = "".join(re.sub(r'[^\w\s]', '', message.from_user.first_name).split())
|
|
||||||
name = morph.parse(namer)[0].inflect({"gent"})
|
|
||||||
|
|
||||||
if name is None: name = namer
|
|
||||||
else: name = name.word
|
|
||||||
|
|
||||||
await message.answer(text=f'*| СТАТИСТИКА {name.upper()} |*\n\n'
|
|
||||||
f'*- За всё время* / *За месяц -*\n'
|
|
||||||
f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n'
|
|
||||||
f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n'
|
|
||||||
f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n'
|
|
||||||
f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n'
|
|
||||||
f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n'
|
|
||||||
f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n'
|
|
||||||
f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*',
|
|
||||||
parse_mode=types.ParseMode.MARKDOWN)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['edit'])
|
|
||||||
async def update(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
|
||||||
|
|
||||||
text_edit = re.sub(r'[^\w\s]', '', message.text.lower()).split()
|
|
||||||
if len(text_edit) == 2:
|
|
||||||
name = morph.parse(text_edit[1])[0]
|
|
||||||
|
|
||||||
if name is None: name = text_edit[1]
|
|
||||||
else: name = name.normal_form
|
|
||||||
|
|
||||||
if name not in list(map(lambda x: x[0], dg.all_names(group_id))):
|
|
||||||
if not db.edit_user_exists(user_id):
|
|
||||||
db.add_edit_user(user_id)
|
|
||||||
|
|
||||||
dg.update_name(user_id, group_id, name)
|
|
||||||
await message.reply(f'{name.title()}, ваше имя было успешно изменено)')
|
|
||||||
else:
|
|
||||||
await message.reply(f'{message.from_user.first_name.lower().title()}, такое имя уже присутствует в чате!')
|
|
||||||
else:
|
|
||||||
await message.reply('Вы не правильно ввели имя! Имя должно быть '
|
|
||||||
'из одного слова и идти сразу после команды!')
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['back_edit'])
|
|
||||||
async def update_return(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
|
||||||
name = re.sub(r'[^\w\s]', '', message.from_user.first_name.lower())
|
|
||||||
|
|
||||||
if db.edit_user_exists(user_id):
|
|
||||||
db.del_edit_user(user_id)
|
|
||||||
dg.update_name(user_id, group_id, name)
|
|
||||||
|
|
||||||
await message.reply(f'{name.title()}, вы успешно вернулись к динамическому изменению имени)')
|
|
||||||
else:
|
|
||||||
await message.reply(f'{name.title()}, вы не устанавливали постоянное имя!')
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['start_bot'])
|
|
||||||
async def opening(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
group_id = du.get_group_id(message.chat.id)
|
|
||||||
if db.check_status(group_id):
|
|
||||||
await message.answer("У вас уже включены текстовые ивенты!")
|
|
||||||
else:
|
|
||||||
db.update_status(group_id)
|
|
||||||
await message.answer("Текстовые ивенты включены!")
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(commands=['stop_bot'])
|
|
||||||
async def closing(message: types.Message):
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
group_id = du.get_group_id(message.chat.id)
|
|
||||||
if db.check_status(group_id):
|
|
||||||
db.update_status(group_id)
|
|
||||||
await message.answer("Текстовые ивенты отключены!")
|
|
||||||
else:
|
|
||||||
await message.answer("У вас уже отключены текстовые ивенты!")
|
|
||||||
|
|
||||||
|
|
||||||
# УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ АВТОМАТИЧЕСКИ
|
|
||||||
@dp.message_handler(content_types=["left_chat_member"])
|
|
||||||
async def delete(message: types.Message):
|
|
||||||
if du.user_exists(message.left_chat_member.id):
|
|
||||||
user_id, group_id = du.get_user_id(message.left_chat_member.id), du.get_group_id(message.chat.id)
|
|
||||||
|
|
||||||
dg.del_user(group_id, user_id)
|
|
||||||
if db.group_exists_month(group_id):
|
|
||||||
if dm.user_exists(user_id, group_id): dm.del_user(group_id, user_id)
|
|
||||||
|
|
||||||
try: await message.delete()
|
|
||||||
except Exception: return
|
|
||||||
|
|
||||||
|
|
||||||
# УДАЛЕНИЕ ТЕХ. СООБЩЕНИЙ
|
|
||||||
@dp.message_handler(content_types=["new_chat_title", "new_chat_photo", "pinned_message", "voice_chat_ended",
|
|
||||||
"voice_chat_participants_invited"])
|
|
||||||
async def chat_events(message: types.Message):
|
|
||||||
try: await message.delete()
|
|
||||||
except Exception: return
|
|
||||||
|
|
||||||
|
|
||||||
# СТАТИСТИКА
|
|
||||||
@dp.message_handler(content_types=['location', 'contact', 'video', 'photo', 'audio', 'document'])
|
|
||||||
async def media(message: types.Message):
|
|
||||||
if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 5, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(content_types=['voice', 'video_note'])
|
|
||||||
async def voice(message: types.Message):
|
|
||||||
if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 7, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(content_types=['sticker'])
|
|
||||||
async def stick(message: types.Message):
|
|
||||||
if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 6, message.from_user.first_name, True)
|
|
||||||
|
|
||||||
|
|
||||||
# ТЕКСТОВЫЕ ИВЕНТЫ
|
|
||||||
@dp.message_handler(content_types=['text'])
|
|
||||||
async def send_events(message: types.Message):
|
|
||||||
group_id, user_id, name = message.chat.id, message.from_user.id, message.from_user.first_name
|
|
||||||
|
|
||||||
# ОБНОВЛЕНИЕ КОЛ-ВО
|
|
||||||
if message.chat.id < 0:
|
|
||||||
upd_stat(user_id, group_id, 1, name) # СООБЩЕНИЙ
|
|
||||||
if len(message.text) > 1 and message.text[0] == '/': upd_stat(user_id, group_id, 3, name) # КОМАНД
|
|
||||||
if 'reply_to_message' in message: upd_stat(user_id, group_id, 2, name) # ОТВЕТОВ НА СООБЩЕНИЯ
|
|
||||||
|
|
||||||
# ПЕРЕМЕННЫЕ
|
|
||||||
low_mes = message.text.lower() # СООБЩЕНИЕ В НИЖНЕМ РЕГИСТРЕ
|
|
||||||
words = message.text.split() # СПИСОК СЛОВ В СООБЩЕНИИ
|
|
||||||
unsigned = re.sub(r'[^\w\s]', '', low_mes).split() # СПИСОК СЛОВ БЕЗ ПУНКТУАЦИИ
|
|
||||||
first_form = [morph.parse(i)[0].normal_form for i in unsigned] # СПИСОК СЛОВ В ПЕРВОЙ ФОРМЕ
|
|
||||||
if message.chat.id < 0: # СПИСОК ИМЕН В СООБЩЕНИИ (ТОЛЬКО В ГРУППЕ)
|
|
||||||
names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))]
|
|
||||||
|
|
||||||
if len(words) >= 2:
|
|
||||||
# ПОЛЕЗНЫЕ ФУНКЦИИ
|
|
||||||
if len(words) == 5 and "число от" in low_mes:
|
|
||||||
await message.answer(
|
|
||||||
text=f"Число <b>[ {random.randint(int(low_mes.split()[2]), int(low_mes.split()[4]))} ]</b>",
|
|
||||||
parse_mode=types.ParseMode.HTML)
|
|
||||||
return
|
|
||||||
|
|
||||||
if unsigned[0] == 'переведи':
|
|
||||||
if "переведи - " in low_mes:
|
|
||||||
await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 1]))
|
|
||||||
elif f"переведи ({unsigned[1]}) - " in low_mes:
|
|
||||||
if len(unsigned[1]) == 1:
|
|
||||||
await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 2], unsigned[1]))
|
|
||||||
return
|
|
||||||
|
|
||||||
if unsigned[0] == 'переверни':
|
|
||||||
if "переверни - " in low_mes:
|
|
||||||
await message.answer(revers(message.text[12:], True))
|
|
||||||
elif "переверни полностью - " in low_mes:
|
|
||||||
await message.answer(revers(message.text[22:], False))
|
|
||||||
return
|
|
||||||
|
|
||||||
if unsigned[0] == 'озвучь' and "озвучь - " in low_mes:
|
|
||||||
text_to_voice = message.text[9:]
|
|
||||||
tts = gTTS(text_to_voice, lang='ru')
|
|
||||||
tts.save('../data/voices/voice.ogg')
|
|
||||||
await bot.send_voice(chat_id=group_id, voice=open('../data/voices/voice.ogg', 'rb'),
|
|
||||||
caption=f"<b>{text_to_voice}</b>", parse_mode=types.ParseMode.HTML)
|
|
||||||
os.remove('../data/voices/voice.ogg')
|
|
||||||
return
|
|
||||||
|
|
||||||
# РАНДОМ ИВЕНТЫ
|
|
||||||
if "подраться" == words[0].lower() and "с" == words[1].lower():
|
|
||||||
text = " ".join([words[i] for i in range(len(words)) if i > 1])
|
|
||||||
|
|
||||||
if random.randint(0, 1) == 0:
|
|
||||||
await message.bot.send_photo(chat_id=group_id,
|
|
||||||
photo=open(f"../data/fight/({random.randint(1, 8)}).jpg", 'rb'),
|
|
||||||
caption=f"{message.from_user.first_name}, ты был унижен {text.title()}"
|
|
||||||
f", с помощью {base.VAR_LOSE[random.randint(0, 3)]}")
|
|
||||||
else:
|
|
||||||
await message.bot.send_photo(chat_id=group_id,
|
|
||||||
photo=open(f"../data/fight/({random.randint(1, 8)}).jpg", 'rb'),
|
|
||||||
caption=f"{message.from_user.first_name}, ты победил в драке "
|
|
||||||
f"с {text.title()}, {base.VAR_WIN[random.randint(0, 1)]}")
|
|
||||||
|
|
||||||
# ИВЕНТ ВЗАИМОДЕЙСТВИЯ
|
|
||||||
for word in base.TMOK_LIST:
|
|
||||||
if word in low_mes:
|
|
||||||
lst = [words[i] for i in range(len(words)) if i != 0]
|
|
||||||
text = " ".join(lst)
|
|
||||||
|
|
||||||
slv = morph.parse(words[0].lower())[0]
|
|
||||||
await message.bot.send_photo(chat_id=group_id,
|
|
||||||
photo=open(f"../data/tmok/({random.randint(1, 4)}).jpg", 'rb'),
|
|
||||||
caption=f"{message.from_user.first_name} "
|
|
||||||
f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}")
|
|
||||||
|
|
||||||
for word in base.KILL_LIST:
|
|
||||||
if word in low_mes:
|
|
||||||
lst = [words[i] for i in range(len(words)) if i != 0]
|
|
||||||
text = " ".join(lst)
|
|
||||||
|
|
||||||
slv = morph.parse(words[0].lower())[0]
|
|
||||||
await message.bot.send_photo(chat_id=group_id,
|
|
||||||
photo=open(f"../data/kill/({random.randint(1, 6)}).jpg", 'rb'),
|
|
||||||
caption=f"{message.from_user.first_name} "
|
|
||||||
f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}")
|
|
||||||
|
|
||||||
if unsigned[0] in base.QUAT_LIST[0] and \
|
|
||||||
unsigned[1] in base.QUAT_LIST[1] and unsigned[2] in base.QUAT_LIST[2]:
|
|
||||||
word = requests.get('http://fucking-great-advice.ru/api/random').json()
|
|
||||||
await message.reply(word["text"])
|
|
||||||
return
|
|
||||||
|
|
||||||
if message.chat.id < 0:
|
|
||||||
# ЛИСТ КОМАНДЫ
|
|
||||||
if names:
|
|
||||||
try:
|
|
||||||
await message.reply(notice(names, False, du.get_group_id(group_id), user_id), types.ParseMode.HTML)
|
|
||||||
except Exception as e:
|
|
||||||
return
|
|
||||||
"""
|
|
||||||
await bot.send_message(chat_id=base.TEX_GROUP, text=f"<b>[ {str(dt.now())[:-10]} ]</b> "
|
|
||||||
f"<b><i>=></i></b> <i>{repr(e)}</i> (уведомления по именам)",
|
|
||||||
parse_mode=types.ParseMode.HTML)
|
|
||||||
"""
|
|
||||||
return
|
|
||||||
|
|
||||||
# ПЕРЕВОДЧИК СЛОВ
|
|
||||||
if checker([i for i in low_mes], words, group_id, user_id, name.lower()) == len(low_mes) and \
|
|
||||||
not any([engl_dict.check(i) for i in unsigned]):
|
|
||||||
await message.reply(f"[{message.from_user.first_name}](tg://user_id?id={user_id}) *>* {translator(words)}",
|
|
||||||
types.ParseMode.MARKDOWN)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
executor.start_polling(dp, skip_updates=True)
|
|
||||||
540
code/handlers.py
Normal file
540
code/handlers.py
Normal file
|
|
@ -0,0 +1,540 @@
|
||||||
|
from aiogram import F, Router
|
||||||
|
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, FSInputFile
|
||||||
|
from aiogram.filters import Command, CommandStart
|
||||||
|
from aiogram.enums import ContentType
|
||||||
|
|
||||||
|
import logging, random, requests, os, re
|
||||||
|
import speech_recognition as sr
|
||||||
|
import soundfile as sf
|
||||||
|
from gtts import gTTS
|
||||||
|
|
||||||
|
from init import *
|
||||||
|
from script import *
|
||||||
|
import base
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
# НОВЫЕ УЧАСТНИКИ ГРУППЫ
|
||||||
|
@router.message(F.content_type == ContentType.NEW_CHAT_MEMBERS)
|
||||||
|
async def notification(message: Message):
|
||||||
|
if not du.group_exists(message.chat.id):
|
||||||
|
du.add_group(message.chat.id)
|
||||||
|
|
||||||
|
group_id = du.get_group_id(message.chat.id)
|
||||||
|
db.add_group(group_id)
|
||||||
|
dg.created_group(group_id)
|
||||||
|
|
||||||
|
await bot.send_message(
|
||||||
|
message.chat.id,
|
||||||
|
f'*Привет группа {message.chat.title}!*\n\n'
|
||||||
|
f'Все функции вы можете узнать по команде /help! Для того, чтобы '
|
||||||
|
f'уведомления по имени и команда /all нормально функционировали, '
|
||||||
|
f'необходимо чтобы каждый участник группы написал хотя бы одно '
|
||||||
|
f'сообщение в чат! Также для того, чтобы системные сообщения удалялись '
|
||||||
|
f'автоматически, необходимо боту выдать права администратора!'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await message.delete()
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ
|
||||||
|
@router.message(F.content_type.in_([ContentType.MIGRATE_TO_CHAT_ID, ContentType.MIGRATE_FROM_CHAT_ID]))
|
||||||
|
async def chat_reload(message: Message):
|
||||||
|
if du.group_exists(message.migrate_from_chat_id):
|
||||||
|
du.update_group_id(du.get_group_id(message.migrate_from_chat_id), message.migrate_to_chat_id)
|
||||||
|
|
||||||
|
# КОМАНДЫ HELP И START
|
||||||
|
@router.message(CommandStart())
|
||||||
|
@router.message(Command('help'))
|
||||||
|
async def helps(message: Message):
|
||||||
|
if message.chat.id > 0:
|
||||||
|
user_id = message.from_user.id
|
||||||
|
if not du.user_exists(user_id):
|
||||||
|
du.add_user(user_id)
|
||||||
|
else:
|
||||||
|
group_id, user_id = message.chat.id, message.from_user.id
|
||||||
|
if not du.user_exists(user_id):
|
||||||
|
du.add_user(user_id)
|
||||||
|
if not du.group_exists(group_id):
|
||||||
|
du.add_group(group_id)
|
||||||
|
upd_stat(user_id, group_id, 3, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
[InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
|
||||||
|
InlineKeyboardButton(text="ИВЕНТЫ", callback_data="even")],
|
||||||
|
[InlineKeyboardButton(text="АВТОР", callback_data="auth"),
|
||||||
|
InlineKeyboardButton(text="ФУНКЦИИ", callback_data="fun")]
|
||||||
|
]
|
||||||
|
|
||||||
|
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await bot.send_voice(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
voice=FSInputFile('../data/tts.ogg'),
|
||||||
|
caption='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, '
|
||||||
|
'ивентами и удобными функциями, которые облегчают использование чата)\n\n'
|
||||||
|
'*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на '
|
||||||
|
'команду /report)',
|
||||||
|
reply_markup=keyboard
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
await bot.send_message(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
text='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, '
|
||||||
|
'ивентами и удобными функциями, которые облегчают использование чата)\n\n'
|
||||||
|
'*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на '
|
||||||
|
'команду /report)',
|
||||||
|
reply_markup=keyboard
|
||||||
|
)
|
||||||
|
|
||||||
|
# INLINE КЛАВИАТУРА ОБРАБОТЧИКИ
|
||||||
|
@router.callback_query(F.data == "auth")
|
||||||
|
async def author(call: CallbackQuery):
|
||||||
|
await call.message.answer(
|
||||||
|
text='*| АВТОР |*\n\n*>>* Этот бот, как бы это не печально звучало, но одна из лучших'
|
||||||
|
' моих работ и если кого-нибудь у меня получится действительно достойный продукт,'
|
||||||
|
' вы сможете о нём узнать в моём телеграм канале *@programium*'
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "fun")
|
||||||
|
async def function(call: CallbackQuery):
|
||||||
|
await call.message.answer(
|
||||||
|
text='*| ФУНКЦИИ |*\n\n*1.* Возможность перевода случайно написанного текста на '
|
||||||
|
'транслите\n*2.* Ведение обширной статистики сообщений\n*3.* Упоминание участника '
|
||||||
|
'при написании его имени в чате\n*4.* Автоматическое удаление системных сообщений'
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "com")
|
||||||
|
async def commands(call: CallbackQuery):
|
||||||
|
await call.message.answer(
|
||||||
|
text='*| КОМАНДЫ |*\n\n*/all* - упомянуть всех в чате\n*/help* - полный список функций\n'
|
||||||
|
'*/recognize* - транскрипция отмеченного голосового сообщения в текст\n'
|
||||||
|
'*/stat_group* - полная статистика группы\n*/stat_user* - полная статистика '
|
||||||
|
'отправителя\n*/edit и /back_edit* - первая команда даёт возможность '
|
||||||
|
'сменить имя для упоминаний на любое слово, а вторая для возврата динамического '
|
||||||
|
'имени\n*/start_bot и /stop_bot* - возможность отключения текстовых ивентов'
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "even")
|
||||||
|
async def events(call: CallbackQuery):
|
||||||
|
await call.message.answer(
|
||||||
|
text='*| ИВЕНТЫ |*\n\n*"Чмокнуть"* - сделать кому-нибудь приятно\n*"Отмудохать"* - '
|
||||||
|
'выместить злость на кого-нибудь\n*"Число от ... до ..."* - случайное значение из '
|
||||||
|
'диапозона\n*"Подраться с ..."* - повод кого-нибудь побить\n*"Переведи (..) - ..."* '
|
||||||
|
'- перевод слова на керпичный язык\n*"Дай блять совет!"* - даёт рандомный охуенный '
|
||||||
|
'совет\n*"Переверни - ..."* - переворачивает слова в предложении\n*"Озвучь - ..."* '
|
||||||
|
'- озвучивает написанный текст'
|
||||||
|
)
|
||||||
|
|
||||||
|
# КОМАНДА ALL
|
||||||
|
@router.message(Command('all'))
|
||||||
|
async def every(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
try:
|
||||||
|
await message.reply(
|
||||||
|
notice(du.get_user_id(message.from_user.id), True,
|
||||||
|
du.get_group_id(message.chat.id), message.from_user.id)
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
await message.reply('В группе состоит менее 3х человек, из-за чего команда не работает!')
|
||||||
|
else:
|
||||||
|
await message.reply('Эта команда предназначена для вызова в чате!')
|
||||||
|
|
||||||
|
# КОМАНДА RECOGNIZE
|
||||||
|
@router.message(Command("recognize"))
|
||||||
|
async def recognise(message: Message):
|
||||||
|
user_id = du.get_user_id(message.from_user.id)
|
||||||
|
|
||||||
|
if message.reply_to_message and message.reply_to_message.voice:
|
||||||
|
num = random.randint(1000, 9999)
|
||||||
|
audio = f"../data/voices/{user_id}_{num}.oga"
|
||||||
|
|
||||||
|
file_id = message.reply_to_message.voice.file_id
|
||||||
|
file = await bot.get_file(file_id)
|
||||||
|
file_path = file.file_path
|
||||||
|
await bot.download_file(file_path, audio)
|
||||||
|
|
||||||
|
data, samplerate = sf.read(audio)
|
||||||
|
os.remove(audio)
|
||||||
|
audio = f"../data/voices/{user_id}_{num}.wav"
|
||||||
|
sf.write(audio, data, samplerate)
|
||||||
|
|
||||||
|
af = sr.AudioFile(audio)
|
||||||
|
r = sr.Recognizer()
|
||||||
|
with af as source:
|
||||||
|
r.pause_threshold = 100
|
||||||
|
source = r.listen(source)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mes = await bot.send_message(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
text="Распознавание.....",
|
||||||
|
reply_to_message_id=message.reply_to_message.message_id
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
query = r.recognize_google(source, language='ru-RU')
|
||||||
|
os.remove(audio)
|
||||||
|
await mes.edit_text(f'*{message.reply_to_message.from_user.first_name} сказал(a)* "{query}"')
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
os.remove(audio)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
await mes.edit_text("Распознать сообщение не удалось!")
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
pass
|
||||||
|
|
||||||
|
# СТАТИСТИКА ГРУППЫ
|
||||||
|
@router.message(Command('stat_group'))
|
||||||
|
async def stat_group(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
group_id = du.get_group_id(message.chat.id)
|
||||||
|
|
||||||
|
group = db.stat_group(group_id)
|
||||||
|
month = db.month_stat_group(group_id)
|
||||||
|
|
||||||
|
await message.answer(
|
||||||
|
text=f'*| СТАТИСТИКА ГРУППЫ |*\n\n'
|
||||||
|
f'*>>* В целом сообщений *[ {message.message_id} ]*\n\n'
|
||||||
|
f'*- За всё время* / *За месяц -*\n'
|
||||||
|
f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n'
|
||||||
|
f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n'
|
||||||
|
f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n'
|
||||||
|
f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n'
|
||||||
|
f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n'
|
||||||
|
f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n'
|
||||||
|
f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*'
|
||||||
|
)
|
||||||
|
|
||||||
|
# СТАТИСТИКА ПОЛЬЗОВАТЕЛЯ
|
||||||
|
@router.message(Command('stat_user'))
|
||||||
|
async def stat_user(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
||||||
|
|
||||||
|
group = dg.stat_user(user_id, group_id)
|
||||||
|
month = dm.stat_user(user_id, group_id)
|
||||||
|
|
||||||
|
namer = "".join(re.sub(r'[^\w\s]', '', message.from_user.first_name).split())
|
||||||
|
name = morph.parse(namer)[0].inflect({"gent"})
|
||||||
|
|
||||||
|
if name is None:
|
||||||
|
name = namer
|
||||||
|
else:
|
||||||
|
name = name.word
|
||||||
|
|
||||||
|
await message.answer(
|
||||||
|
text=f'*| СТАТИСТИКА {name.upper()} |*\n\n'
|
||||||
|
f'*- За всё время* / *За месяц -*\n'
|
||||||
|
f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n'
|
||||||
|
f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n'
|
||||||
|
f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n'
|
||||||
|
f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n'
|
||||||
|
f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n'
|
||||||
|
f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n'
|
||||||
|
f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*'
|
||||||
|
)
|
||||||
|
|
||||||
|
# РЕДАКТИРОВАНИЕ ИМЕНИ
|
||||||
|
@router.message(Command('edit'))
|
||||||
|
async def update(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
||||||
|
|
||||||
|
text_edit = re.sub(r'[^\w\s]', '', message.text.lower()).split()
|
||||||
|
if len(text_edit) == 2:
|
||||||
|
name = morph.parse(text_edit[1])[0]
|
||||||
|
|
||||||
|
if name is None:
|
||||||
|
name = text_edit[1]
|
||||||
|
else:
|
||||||
|
name = name.normal_form
|
||||||
|
|
||||||
|
if name not in list(map(lambda x: x[0], dg.all_names(group_id))):
|
||||||
|
if not db.edit_user_exists(user_id):
|
||||||
|
db.add_edit_user(user_id)
|
||||||
|
|
||||||
|
dg.update_name(user_id, group_id, name)
|
||||||
|
await message.reply(f'{name.title()}, ваше имя было успешно изменено)')
|
||||||
|
else:
|
||||||
|
await message.reply(f'{message.from_user.first_name.lower().title()}, такое имя уже присутствует в чате!')
|
||||||
|
else:
|
||||||
|
await message.reply('Вы не правильно ввели имя! Имя должно быть '
|
||||||
|
'из одного слова и идти сразу после команды!')
|
||||||
|
|
||||||
|
# ВОЗВРАТ К ДИНАМИЧЕСКОМУ ИМЕНИ
|
||||||
|
@router.message(Command('back_edit'))
|
||||||
|
async def update_return(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id)
|
||||||
|
name = re.sub(r'[^\w\s]', '', message.from_user.first_name.lower())
|
||||||
|
|
||||||
|
if db.edit_user_exists(user_id):
|
||||||
|
db.del_edit_user(user_id)
|
||||||
|
dg.update_name(user_id, group_id, name)
|
||||||
|
|
||||||
|
await message.reply(f'{name.title()}, вы успешно вернулись к динамическому изменению имени)')
|
||||||
|
else:
|
||||||
|
await message.reply(f'{name.title()}, вы не устанавливали постоянное имя!')
|
||||||
|
|
||||||
|
# ВКЛЮЧЕНИЕ ТЕКСТОВЫХ ИВЕНТОВ
|
||||||
|
@router.message(Command('start_bot'))
|
||||||
|
async def opening(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
group_id = du.get_group_id(message.chat.id)
|
||||||
|
if db.check_status(group_id):
|
||||||
|
await message.answer("У вас уже включены текстовые ивенты!")
|
||||||
|
else:
|
||||||
|
db.update_status(group_id)
|
||||||
|
await message.answer("Текстовые ивенты включены!")
|
||||||
|
|
||||||
|
# ОТКЛЮЧЕНИЕ ТЕКСТОВЫХ ИВЕНТОВ
|
||||||
|
@router.message(Command('stop_bot'))
|
||||||
|
async def closing(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
group_id = du.get_group_id(message.chat.id)
|
||||||
|
if db.check_status(group_id):
|
||||||
|
db.update_status(group_id)
|
||||||
|
await message.answer("Текстовые ивенты отключены!")
|
||||||
|
else:
|
||||||
|
await message.answer("У вас уже отключены текстовые ивенты!")
|
||||||
|
|
||||||
|
# УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ АВТОМАТИЧЕСКИ
|
||||||
|
@router.message(F.content_type == ContentType.LEFT_CHAT_MEMBER)
|
||||||
|
async def delete(message: Message):
|
||||||
|
if du.user_exists(message.left_chat_member.id):
|
||||||
|
user_id, group_id = du.get_user_id(message.left_chat_member.id), du.get_group_id(message.chat.id)
|
||||||
|
|
||||||
|
dg.del_user(group_id, user_id)
|
||||||
|
if db.group_exists_month(group_id):
|
||||||
|
if dm.user_exists(user_id, group_id):
|
||||||
|
dm.del_user(group_id, user_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await message.delete()
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
# УДАЛЕНИЕ ТЕХНИЧЕСКИХ СООБЩЕНИЙ
|
||||||
|
@router.message(F.content_type.in_([
|
||||||
|
ContentType.NEW_CHAT_TITLE,
|
||||||
|
ContentType.NEW_CHAT_PHOTO,
|
||||||
|
ContentType.PINNED_MESSAGE,
|
||||||
|
ContentType.VIDEO_CHAT_ENDED,
|
||||||
|
ContentType.VIDEO_CHAT_PARTICIPANTS_INVITED
|
||||||
|
]))
|
||||||
|
async def chat_events(message: Message):
|
||||||
|
try:
|
||||||
|
await message.delete()
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
# МЕДИА ФАЙЛЫ
|
||||||
|
@router.message(F.content_type.in_([
|
||||||
|
ContentType.LOCATION,
|
||||||
|
ContentType.CONTACT,
|
||||||
|
ContentType.VIDEO,
|
||||||
|
ContentType.PHOTO,
|
||||||
|
ContentType.AUDIO,
|
||||||
|
ContentType.DOCUMENT
|
||||||
|
]))
|
||||||
|
async def media(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 5, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
# ГОЛОСОВЫЕ СООБЩЕНИЯ И КРУЖОЧКИ
|
||||||
|
@router.message(F.content_type.in_([ContentType.VOICE, ContentType.VIDEO_NOTE]))
|
||||||
|
async def voice(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 7, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
if message.voice and message.chat.id < 0:
|
||||||
|
if message.voice.duration <= 60:
|
||||||
|
user_id = du.get_user_id(message.from_user.id)
|
||||||
|
|
||||||
|
num = random.randint(1000, 9999)
|
||||||
|
audio = f"../data/voices/{user_id}_{num}.oga"
|
||||||
|
|
||||||
|
file_id = message.voice.file_id
|
||||||
|
file = await bot.get_file(file_id)
|
||||||
|
file_path = file.file_path
|
||||||
|
await bot.download_file(file_path, audio)
|
||||||
|
|
||||||
|
data, samplerate = sf.read(audio)
|
||||||
|
os.remove(audio)
|
||||||
|
audio = f"../data/voices/{user_id}_{num}.wav"
|
||||||
|
sf.write(audio, data, samplerate)
|
||||||
|
|
||||||
|
af = sr.AudioFile(audio)
|
||||||
|
r = sr.Recognizer()
|
||||||
|
with af as source:
|
||||||
|
r.pause_threshold = 100
|
||||||
|
source = r.listen(source)
|
||||||
|
|
||||||
|
try:
|
||||||
|
query = r.recognize_google(source, language='ru-RU')
|
||||||
|
os.remove(audio)
|
||||||
|
|
||||||
|
group_id = message.chat.id
|
||||||
|
unsigned = re.sub(r'[^\w\s]', '', query.lower()).split()
|
||||||
|
first_form = [morph.parse(i)[0].normal_form for i in unsigned]
|
||||||
|
names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))]
|
||||||
|
|
||||||
|
if names:
|
||||||
|
await message.reply(notice(names, False, du.get_group_id(group_id), message.from_user.id))
|
||||||
|
return
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
os.remove(audio)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# СТИКЕРЫ
|
||||||
|
@router.message(F.content_type == ContentType.STICKER)
|
||||||
|
async def stick(message: Message):
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(message.from_user.id, message.chat.id, 6, message.from_user.first_name, True)
|
||||||
|
|
||||||
|
# ТЕКСТОВЫЕ ИВЕНТЫ
|
||||||
|
@router.message(F.content_type == ContentType.TEXT)
|
||||||
|
async def send_events(message: Message):
|
||||||
|
group_id, user_id, name = message.chat.id, message.from_user.id, message.from_user.first_name
|
||||||
|
|
||||||
|
# ОБНОВЛЕНИЕ СТАТИСТИКИ
|
||||||
|
if message.chat.id < 0:
|
||||||
|
upd_stat(user_id, group_id, 1, name) # СООБЩЕНИЙ
|
||||||
|
if len(message.text) > 1 and message.text[0] == '/':
|
||||||
|
upd_stat(user_id, group_id, 3, name) # КОМАНД
|
||||||
|
if message.reply_to_message:
|
||||||
|
upd_stat(user_id, group_id, 2, name) # ОТВЕТОВ НА СООБЩЕНИЯ
|
||||||
|
|
||||||
|
# ПЕРЕМЕННЫЕ
|
||||||
|
low_mes = message.text.lower()
|
||||||
|
words = message.text.split()
|
||||||
|
unsigned = re.sub(r'[^\w\s]', '', low_mes).split()
|
||||||
|
first_form = [morph.parse(i)[0].normal_form for i in unsigned]
|
||||||
|
|
||||||
|
if message.chat.id < 0:
|
||||||
|
names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))]
|
||||||
|
|
||||||
|
if len(words) >= 2:
|
||||||
|
# ПОЛЕЗНЫЕ ФУНКЦИИ
|
||||||
|
if len(words) == 5 and "число от" in low_mes:
|
||||||
|
try:
|
||||||
|
num1, num2 = int(low_mes.split()[2]), int(low_mes.split()[4])
|
||||||
|
await message.answer(
|
||||||
|
text=f"Число *[ {random.randint(num1, num2)} ]*"
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
if unsigned[0] == 'переведи':
|
||||||
|
if "переведи - " in low_mes:
|
||||||
|
await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 1]))
|
||||||
|
elif f"переведи ({unsigned[1]}) - " in low_mes:
|
||||||
|
if len(unsigned[1]) == 1:
|
||||||
|
await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 2], unsigned[1]))
|
||||||
|
return
|
||||||
|
|
||||||
|
if unsigned[0] == 'переверни':
|
||||||
|
if "переверни - " in low_mes:
|
||||||
|
await message.answer(revers(message.text[12:], True))
|
||||||
|
elif "переверни полностью - " in low_mes:
|
||||||
|
await message.answer(revers(message.text[22:], False))
|
||||||
|
return
|
||||||
|
|
||||||
|
if unsigned[0] == 'озвучь' and "озвучь - " in low_mes:
|
||||||
|
text_to_voice = message.text[9:]
|
||||||
|
tts = gTTS(text_to_voice, lang='ru')
|
||||||
|
tts.save('../data/voices/voice.ogg')
|
||||||
|
await bot.send_voice(
|
||||||
|
chat_id=group_id,
|
||||||
|
voice=FSInputFile('../data/voices/voice.ogg'),
|
||||||
|
caption=f"*{text_to_voice}*"
|
||||||
|
)
|
||||||
|
os.remove('../data/voices/voice.ogg')
|
||||||
|
return
|
||||||
|
|
||||||
|
# РАНДОМ ИВЕНТЫ
|
||||||
|
if "подраться" == words[0].lower() and "с" == words[1].lower():
|
||||||
|
text = " ".join([words[i] for i in range(len(words)) if i > 1])
|
||||||
|
|
||||||
|
if random.randint(0, 1) == 0:
|
||||||
|
await message.answer_photo(
|
||||||
|
photo=FSInputFile(f"../data/fight/({random.randint(1, 8)}).jpg"),
|
||||||
|
caption=f"{message.from_user.first_name}, ты был унижен {text.title()}"
|
||||||
|
f", с помощью {base.VAR_LOSE[random.randint(0, 3)]}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.answer_photo(
|
||||||
|
photo=FSInputFile(f"../data/fight/({random.randint(1, 8)}).jpg"),
|
||||||
|
caption=f"{message.from_user.first_name}, ты победил в драке "
|
||||||
|
f"с {text.title()}, {base.VAR_WIN[random.randint(0, 1)]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ИВЕНТ ВЗАИМОДЕЙСТВИЯ
|
||||||
|
for word in base.TMOK_LIST:
|
||||||
|
if word in low_mes:
|
||||||
|
lst = [words[i] for i in range(len(words)) if i != 0]
|
||||||
|
text = " ".join(lst)
|
||||||
|
|
||||||
|
slv = morph.parse(words[0].lower())[0]
|
||||||
|
await message.answer_photo(
|
||||||
|
photo=FSInputFile(f"../data/tmok/({random.randint(1, 4)}).jpg"),
|
||||||
|
caption=f"{message.from_user.first_name} "
|
||||||
|
f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for word in base.KILL_LIST:
|
||||||
|
if word in low_mes:
|
||||||
|
lst = [words[i] for i in range(len(words)) if i != 0]
|
||||||
|
text = " ".join(lst)
|
||||||
|
|
||||||
|
slv = morph.parse(words[0].lower())[0]
|
||||||
|
await message.answer_photo(
|
||||||
|
photo=FSInputFile(f"../data/kill/({random.randint(1, 6)}).jpg"),
|
||||||
|
caption=f"{message.from_user.first_name} "
|
||||||
|
f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (unsigned[0] in base.QUAT_LIST[0] and
|
||||||
|
unsigned[1] in base.QUAT_LIST[1] and
|
||||||
|
unsigned[2] in base.QUAT_LIST[2]):
|
||||||
|
try:
|
||||||
|
word = requests.get('http://fucking-great-advice.ru/api/random').json()
|
||||||
|
await message.reply(word["text"])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
if message.chat.id < 0:
|
||||||
|
# УПОМИНАНИЯ ПО ИМЕНАМ
|
||||||
|
if names:
|
||||||
|
try:
|
||||||
|
await message.reply(notice(names, False, du.get_group_id(group_id), user_id))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
# ПЕРЕВОДЧИК СЛОВ
|
||||||
|
if (checker([i for i in low_mes], words, group_id, user_id, name.lower()) == len(low_mes) and
|
||||||
|
not any([engl_dict.check(i) for i in unsigned if len(i) > 1])):
|
||||||
|
await message.reply(
|
||||||
|
f"[{message.from_user.first_name}](tg://user_id?id={user_id}) *>* {translator(words)}"
|
||||||
|
)
|
||||||
|
return
|
||||||
21
code/init.py
Normal file
21
code/init.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram.enums.parse_mode import ParseMode
|
||||||
|
from aiogram.fsm.storage.memory import MemoryStorage
|
||||||
|
from aiogram.client.bot import DefaultBotProperties
|
||||||
|
|
||||||
|
|
||||||
|
import base, enchant, pymorphy3
|
||||||
|
|
||||||
|
bot = Bot(token=base.TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.MARKDOWN))
|
||||||
|
dp = Dispatcher(storage=MemoryStorage())
|
||||||
|
|
||||||
|
morph = pymorphy3.MorphAnalyzer()
|
||||||
|
engl_dict = enchant.Dict("en_US")
|
||||||
|
|
||||||
|
|
||||||
|
import sql
|
||||||
|
|
||||||
|
db = sql.Base('../db/base.db')
|
||||||
|
du = sql.User('../db/users.db')
|
||||||
|
dg = sql.Group('../db/groups.db')
|
||||||
|
dm = sql.Month('../db/month.db')
|
||||||
|
|
@ -63,8 +63,7 @@ def notice(name, all_users, group_id, author):
|
||||||
|
|
||||||
if all_users:
|
if all_users:
|
||||||
name = dg.user_name(name, group_id)
|
name = dg.user_name(name, group_id)
|
||||||
usr = ["<a href=\""+'tg://user?id='+str(ids[i])+"\">"+names[i].title()+"</a>" for i in range(len(names))
|
usr = [f"[{names[i].title()}](tg://user?id={str(ids[i])})" for i in range(len(names)) if names[i] != name.lower()]
|
||||||
if names[i] != name.lower()]
|
|
||||||
usr.append(f'{usr[-2]} и {usr[-1]}')
|
usr.append(f'{usr[-2]} и {usr[-1]}')
|
||||||
del usr[-2], usr[-2]
|
del usr[-2], usr[-2]
|
||||||
return f'{", ".join(usr)} вас вызывает {name.title()}'
|
return f'{", ".join(usr)} вас вызывает {name.title()}'
|
||||||
|
|
@ -75,13 +74,12 @@ def notice(name, all_users, group_id, author):
|
||||||
no_copy.append(i)
|
no_copy.append(i)
|
||||||
|
|
||||||
if len(no_copy) > 1: # ПЕРЕПИСАТЬ КОД ГАВНА КУСОК
|
if len(no_copy) > 1: # ПЕРЕПИСАТЬ КОД ГАВНА КУСОК
|
||||||
usr = ["<a href=\""+'tg://user?id='+str(ids[names.index(_)])+"\">"+_.title()+"</a>" for _ in no_copy
|
usr = [f"[{_.title()}](tg://user?id={str(ids[names.index(_)])})" for _ in no_copy if int(author) != ids[names.index(_)]]
|
||||||
if int(author) != ids[names.index(_)]]
|
|
||||||
usr.append(f'{usr[-2]} и {usr[-1]}')
|
usr.append(f'{usr[-2]} и {usr[-1]}')
|
||||||
del usr[-2], usr[-2]
|
del usr[-2], usr[-2]
|
||||||
return f"{', '.join(usr)} вас упомянули)"
|
return f"{', '.join(usr)} вас упомянули)"
|
||||||
else:
|
else:
|
||||||
usr = "<a href=\""+'tg://user?id='+str(ids[names.index(no_copy[0])])+"\">"+no_copy[0].title()+"</a>"
|
usr = f"[{no_copy[0].title()}](tg://user?id={str(ids[names.index(no_copy[0])])})"
|
||||||
return f"{usr}, тебя упомянули)"
|
return f"{usr}, тебя упомянули)"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
BIN
data/voices/1_7047.oga
Normal file
BIN
data/voices/1_7047.oga
Normal file
Binary file not shown.
1
data/Текст озвучки.txt
Normal file
1
data/Текст озвучки.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
- - Здраствуйте! Это АБ+ОБОТ, который поможет вам комфортнее провести время в чате. Бот может упомянуть человека, если его имя было упомянуто в сообщении, вызвать всех участников чата, перевести слово с транслита на русский и с русского на кирпичный, а также имеет +уйму интересных функций описаных ниже! - Приятного использования! - -
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
libraries:
|
|
||||||
|
|
||||||
pip install random2, pymorphy2, requests, emoji, re, aiogram
|
|
||||||
34
requirements.txt
Normal file
34
requirements.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Core Framework Dependencies
|
||||||
|
aiogram==3.10.0
|
||||||
|
asyncio-mqtt==0.16.1
|
||||||
|
|
||||||
|
# Database Management
|
||||||
|
sqlite3
|
||||||
|
|
||||||
|
# Natural Language Processing
|
||||||
|
pymorphy3==1.2.1
|
||||||
|
pymorphy3-dicts-ru==2.4.417150.4580142
|
||||||
|
enchant==1.6.6
|
||||||
|
|
||||||
|
# Speech Recognition & Synthesis
|
||||||
|
SpeechRecognition==3.10.4
|
||||||
|
gTTS==2.5.1
|
||||||
|
soundfile==0.12.1
|
||||||
|
|
||||||
|
# HTTP Client for API Integration
|
||||||
|
requests==2.31.0
|
||||||
|
|
||||||
|
# Audio Processing Dependencies
|
||||||
|
pyaudio==0.2.14
|
||||||
|
pydub==0.25.1
|
||||||
|
|
||||||
|
# System Dependencies (if needed)
|
||||||
|
# Note: Some packages may require system-level installation
|
||||||
|
# Ubuntu/Debian: sudo apt-get install python3-enchant libenchant-2-2
|
||||||
|
# macOS: brew install enchant portaudio
|
||||||
|
# Windows: Download pyaudio wheel from unofficial binaries
|
||||||
|
|
||||||
|
# Development Dependencies (Optional)
|
||||||
|
# pytest==8.2.2
|
||||||
|
# black==24.4.2
|
||||||
|
# flake8==7.1.0
|
||||||
Loading…
Add table
Reference in a new issue