From 2e1e74450b03e40f3566a4ecae0751064023c91e Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Fri, 7 Jul 2023 15:58:10 +0300 Subject: [PATCH 1/7] f --- .github/workflows/linter.yml | 21 ++++++++++++++++ .pylintrc | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 .github/workflows/linter.yml create mode 100644 .pylintrc diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..50ed129 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,21 @@ +name: PEP8 Style Guide Enforcement + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pylint + - name: Run Pylint + run: | + pylint $(git ls-files '*.py') diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..d01c1d7 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,46 @@ +[BASIC] + +argument-naming-style=snake_case +attr-naming-style=snake_case + +bad-names= + foo, + bar, + baz, + toto, + tutu, + tata + +class-const-naming-style=UPPER_CASE +class-naming-style=PascalCase +const-naming-style=UPPER_CASE +docstring-min-length=-1 +function-naming-style=snake_case +method-naming-style=snake_case +module-naming-style=snake_case +variable-naming-style=snake_case + + +[MESSAGES CONTROL] +disable= + missing-module-docstring, + missing-class-docstring, + missing-function-docstring, + consider-using-dict-items, + consider-iterating-dictionary + +enable= + import-error, + invalid-name, + unused-argument, + unused-import, + missing-final-newline + +[FORMAT] +max-line-length=120 +max-module-lines=1000 + +[DESIGN] +max-args=6 +max-branches=12 +max-returns=6 From 194aff8a8649d972a7eb708a635d05ad1c9703bb Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Wed, 12 Jul 2023 10:47:50 +0300 Subject: [PATCH 2/7] pass all --- .pylintrc | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/.pylintrc b/.pylintrc index d01c1d7..4445d7a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -23,18 +23,51 @@ variable-naming-style=snake_case [MESSAGES CONTROL] disable= + import-error, + invalid-name, + unused-argument, + unused-import, + missing-final-newline, + line-too-long, + wrong-import-order, + wildcard-import, + trailing-whitespace, + cyclic-import, + unused-wildcard-import, + trailing-newlines, + redefined-builtin, + singleton-comparison, + unused-variable, + no-else-return, + f-string-without-interpolation, + ungrouped-imports, + too-many-arguments, + consider-using-with, + protected-access, + inconsistent-return-statements, + simplifiable-condition, + reimported, + no-member, + super-with-arguments, + + fixme, missing-module-docstring, missing-class-docstring, missing-function-docstring, consider-using-dict-items, - consider-iterating-dictionary + consider-iterating-dictionary, + too-few-public-methods, + unspecified-encoding, + consider-using-enumerate, + subprocess-run-check, + redefined-outer-name -enable= - import-error, - invalid-name, - unused-argument, - unused-import, - missing-final-newline +; enable= +; import-error, +; invalid-name, +; unused-argument, +; unused-import, +; missing-final-newline [FORMAT] max-line-length=120 From f5e52efec1daa5c21c722aad99e447cbb259fec1 Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Wed, 12 Jul 2023 10:48:38 +0300 Subject: [PATCH 3/7] move muted rules to enabled ones --- .pylintrc | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/.pylintrc b/.pylintrc index 4445d7a..f3a9657 100644 --- a/.pylintrc +++ b/.pylintrc @@ -23,6 +23,19 @@ variable-naming-style=snake_case [MESSAGES CONTROL] disable= + fixme, + missing-module-docstring, + missing-class-docstring, + missing-function-docstring, + consider-using-dict-items, + consider-iterating-dictionary, + too-few-public-methods, + unspecified-encoding, + consider-using-enumerate, + subprocess-run-check, + redefined-outer-name + +enable= import-error, invalid-name, unused-argument, @@ -48,26 +61,7 @@ disable= simplifiable-condition, reimported, no-member, - super-with-arguments, - - fixme, - missing-module-docstring, - missing-class-docstring, - missing-function-docstring, - consider-using-dict-items, - consider-iterating-dictionary, - too-few-public-methods, - unspecified-encoding, - consider-using-enumerate, - subprocess-run-check, - redefined-outer-name - -; enable= -; import-error, -; invalid-name, -; unused-argument, -; unused-import, -; missing-final-newline + super-with-arguments [FORMAT] max-line-length=120 From d68a04f0e0434b13dcc236e8cb200387e459acb6 Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Fri, 21 Jul 2023 12:32:28 +0300 Subject: [PATCH 4/7] linter fixes --- .github/workflows/linter.yml | 2 + .pylintrc | 16 +-- TestPayment/config.py | 2 +- TestPayment/pay_bot.py | 10 +- audio_classes.py | 8 +- bot.py | 103 ++++++++++------ db.py | 176 ++++++++++++++++++--------- emotional_speech_recognizing/main.py | 27 ++-- keyboard.py | 4 +- my_cron.py | 1 - requirements.txt | 4 +- script_engine.py | 54 +++++--- silero_demo/bot.py | 18 +-- silero_demo/silero_test.py | 50 ++++---- silero_module.py | 1 - test_script_engine.py | 119 ++++++++++++++---- voice_module.py | 20 ++- 17 files changed, 406 insertions(+), 209 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 50ed129..ac5d02b 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -15,6 +15,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + pip install -r emotional_speech_recognizing/requirements.txt + pip install -r silero_demo/requirements.txt pip install pylint - name: Run Pylint run: | diff --git a/.pylintrc b/.pylintrc index f3a9657..59f159a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -33,19 +33,23 @@ disable= unspecified-encoding, consider-using-enumerate, subprocess-run-check, - redefined-outer-name + redefined-outer-name, + no-member, + unused-argument, + protected-access, + duplicate-code, + missing-timeout, + cyclic-import # это сложно поправить быстро enable= import-error, invalid-name, - unused-argument, unused-import, missing-final-newline, line-too-long, wrong-import-order, wildcard-import, trailing-whitespace, - cyclic-import, unused-wildcard-import, trailing-newlines, redefined-builtin, @@ -56,18 +60,16 @@ enable= ungrouped-imports, too-many-arguments, consider-using-with, - protected-access, inconsistent-return-statements, simplifiable-condition, reimported, - no-member, super-with-arguments [FORMAT] -max-line-length=120 +max-line-length=150 max-module-lines=1000 [DESIGN] -max-args=6 +max-args=9 max-branches=12 max-returns=6 diff --git a/TestPayment/config.py b/TestPayment/config.py index 38d360e..4c1d892 100644 --- a/TestPayment/config.py +++ b/TestPayment/config.py @@ -1,2 +1,2 @@ BOT_TOKEN = '1764779366:AAHPNU-fgWI1PEl_odMuNFMf7E767lHfKC4' -PROVIDER_TOKEN = '401643678:TEST:e1dc6c64-5f3f-4d0d-a7c7-f2f2bea0aa4e' \ No newline at end of file +PROVIDER_TOKEN = '401643678:TEST:e1dc6c64-5f3f-4d0d-a7c7-f2f2bea0aa4e' diff --git a/TestPayment/pay_bot.py b/TestPayment/pay_bot.py index ba9ecad..a8a215c 100644 --- a/TestPayment/pay_bot.py +++ b/TestPayment/pay_bot.py @@ -7,14 +7,13 @@ import logging import config -from telegram import LabeledPrice, ShippingOption, Update +from telegram import LabeledPrice, Update from telegram.ext import ( Updater, CommandHandler, MessageHandler, Filters, PreCheckoutQueryHandler, - ShippingQueryHandler, CallbackContext, ) @@ -37,7 +36,8 @@ def start_without_shipping_callback(update: Update, context: CallbackContext) -> description = "Payment Example using python-telegram-bot" # select a payload just for you to recognize its the donation from your bot payload = "Custom-Payload" - # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token + # In order to get a provider_token see + # https://core.telegram.org/bots/payments#getting-a-token provider_token = config.PROVIDER_TOKEN start_parameter = "test-payment" currency = "RUB" @@ -48,9 +48,7 @@ def start_without_shipping_callback(update: Update, context: CallbackContext) -> # optionally pass need_name=True, need_phone_number=True, # need_email=True, need_shipping_address=True, is_flexible=True - context.bot.send_invoice( - chat_id, title, description, payload, provider_token, start_parameter, currency, prices - ) + context.bot.send_invoice(chat_id, title, description, payload, provider_token, start_parameter, currency, prices) # after (optional) shipping, it's the pre-checkout diff --git a/audio_classes.py b/audio_classes.py index 3402792..4b248c6 100644 --- a/audio_classes.py +++ b/audio_classes.py @@ -1,4 +1,3 @@ -import json from dataclasses import dataclass @@ -24,10 +23,11 @@ def __add_word(self, word, start, end, conf): def generate_output_info(self): answer_list = [f"Полученное предложение: \n{self._text}\nСтатистика по сообщению:\n"] for i in self._words: - answer_list.append(f"Слово \"{i.word}\" было сказано в промежутке {i.begin_timestamp} - {i.end_timestamp} с " - f"вероятностью {i.probability}\n") + answer_list.append( + f"Слово \"{i.word}\" было сказано в промежутке {i.begin_timestamp} - {i.end_timestamp} с " + f"вероятностью {i.probability}\n" + ) return "".join(answer_list) def generate_stats(self): return '\n'.join([f"{i.word} - {i.begin_timestamp} - {i.end_timestamp} - {i.probability}" for i in self._words]) - diff --git a/bot.py b/bot.py index fc4b3e9..6a23be9 100644 --- a/bot.py +++ b/bot.py @@ -1,20 +1,41 @@ import sys -import os import queue -import sys import threading from telegram import Update -from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext, \ - ConversationHandler, MessageHandler, Filters +from telegram.ext import ( + Updater, + CommandHandler, + CallbackQueryHandler, + CallbackContext, + ConversationHandler, + MessageHandler, + Filters, +) import my_cron -from db import push_user_feeling, push_user_focus, push_user_schedule, get_user_feelings, \ - set_user_ready_flag, set_schedule_asked_today, init_user, get_schedule_by_user, auth_in_db, set_last_usage, \ - get_users_not_answer_last24hours, get_users_not_finish_survey, push_bot_answer, get_bot_audio -from keyboard import daily_schedule_keyboard, mood_keyboard, focus_keyboard, ready_keyboard, \ - menu_kyeboard, VALUES +from db import ( + push_user_feeling, + push_user_focus, + push_user_schedule, + get_user_feelings, + set_user_ready_flag, + set_schedule_asked_today, + init_user, + get_schedule_by_user, + auth_in_db, set_last_usage, + get_users_not_answer_last24hours, + get_users_not_finish_survey, +) +from keyboard import ( + daily_schedule_keyboard, + mood_keyboard, + focus_keyboard, + ready_keyboard, + menu_kyeboard, + VALUES, +) from logs import init_logger from script_engine import Engine from voice_module import work_with_audio @@ -33,16 +54,22 @@ def start(update: Update, context: CallbackContext) -> str: user = init_user(update.effective_user) set_last_usage(user) - update.message.reply_text('Привет! Я бот, который поможет тебе отрефлексировать твое настроение', - reply_markup=menu_kyeboard()) - update.message.reply_text('В какое время тебе удобно подводить итоги дня?', reply_markup=daily_schedule_keyboard()) + update.message.reply_text( + 'Привет! Я бот, который поможет тебе отрефлексировать твое настроение', + reply_markup=menu_kyeboard() + ) + update.message.reply_text( + 'В какое время тебе удобно подводить итоги дня?', + reply_markup=daily_schedule_keyboard() + ) def ask_focus(update: Update) -> None: update.effective_user.send_message( 'Подведение итогов дня поможет исследовать определенные сложности и паттерны твоего поведения. ' 'Каждую неделю можно выбирать разные фокусы или один и тот же. Выбрать фокус этой недели:', - reply_markup=focus_keyboard()) + reply_markup=focus_keyboard() + ) # def button(update: Update, context: CallbackContext) -> int: @@ -64,14 +91,18 @@ def button(update: Update, context: CallbackContext) -> str: # User entered week focus set_user_ready_flag(update.effective_user, True) push_user_focus(update.effective_user, query.data, update.effective_message.date) - return engine_callback(update, context) + elif query.data.startswith('r_') and ( - last_message == 'Привет! Пришло время подводить итоги. Давай?' or "Продолжить прохождение опроса?"): + last_message in [ + 'Привет! Пришло время подводить итоги. Давай?', + 'Продолжить прохождение опроса?' + ] + ): if query.data == 'r_yes': return engine_callback(update, context) - elif query.data == 'r_1h': - text = f'Понял тебя. Спрошу через час' + if query.data == 'r_1h': + text = 'Понял тебя. Спрошу через час' query.edit_message_text(text=text) set_user_ready_flag(update.effective_user, True) @@ -91,6 +122,7 @@ def button(update: Update, context: CallbackContext) -> str: if len(schedule.sending_list) < DAYS_OFFSET: schedule.is_on = True schedule.save() + return '' def text_processing(update: Update, context: CallbackContext): @@ -100,12 +132,12 @@ def text_processing(update: Update, context: CallbackContext): elif update.message.text == VALUES['menu_change_focus']: change_focus(update, context) elif update.message.text == VALUES['menu_help']: - help(update, context) + user_help(update, context) else: engine_callback(update, context) -def help(update: Update, context: CallbackContext) -> None: +def user_help(update: Update, context: CallbackContext) -> None: user = init_user(update.effective_user) set_last_usage(user) # TODO сделать справку @@ -123,7 +155,7 @@ def debug_get_users_not_answer_last24hours(update: Update, context: CallbackCont def error(update: Update, context: CallbackContext) -> None: - update.message.reply_text(f'Error!') + update.message.reply_text('Error!') def debug_get_users_not_finish_survey(update: Update, context: CallbackContext): @@ -133,8 +165,11 @@ def debug_get_users_not_finish_survey(update: Update, context: CallbackContext): def ask_ready(updater, schedule): # set_schedule_is_on_flag(schedule, False) set_schedule_asked_today(schedule) - updater.bot.send_message(schedule.user.id, "Привет! Пришло время подводить итоги. Давай?", - reply_markup=ready_keyboard()) + updater.bot.send_message( + schedule.user.id, + "Привет! Пришло время подводить итоги. Давай?", + reply_markup=ready_keyboard() + ) def resume_survey(updater, user) -> None: @@ -164,16 +199,17 @@ def change_focus(update: Update, context: CallbackContext): set_last_usage(user) update.effective_user.send_message( 'Выберете новый фокус:', - reply_markup=focus_keyboard()) + reply_markup=focus_keyboard() + ) def send_audio_answer(update: Update, context: CallbackContext): - + update.effective_user.send_message("Уже обрабатываю твоё сообщение") - - text = update.message.text#'Спасибо, что поделился своими переживаниями' + + text = update.message.text # 'Спасибо, что поделился своими переживаниями' audio = bot_answer_audio(text) - + if audio: update.effective_user.send_voice(voice=audio.content) # push_bot_answer(update.update_id, answer=audio.content, text=text) @@ -192,12 +228,11 @@ def main(token, mode): elif mode == "text": updater.dispatcher.add_handler(CommandHandler('start', start)) - updater.dispatcher.add_handler(CommandHandler('help', help)) + updater.dispatcher.add_handler(CommandHandler('user_help', user_help)) updater.dispatcher.add_handler(CommandHandler('stats', stats)) updater.dispatcher.add_handler(CommandHandler('change_focus', change_focus)) updater.dispatcher.add_handler(CommandHandler('get_users_not_finish_survey', debug_get_users_not_finish_survey)) - updater.dispatcher.add_handler( - CommandHandler('get_users_not_answer_last24hours', debug_get_users_not_answer_last24hours)) + updater.dispatcher.add_handler(CommandHandler('get_users_not_answer_last24hours', debug_get_users_not_answer_last24hours)) updater.dispatcher.add_handler(CommandHandler('cancel', cancel)) updater.dispatcher.add_handler(CallbackQueryHandler(button)) @@ -208,7 +243,7 @@ def main(token, mode): class Worker(threading.Thread): def __init__(self, tokens_queue): - super(Worker, self).__init__() + super().__init__() self.work_queue = tokens_queue def run(self): @@ -218,9 +253,9 @@ def run(self): finally: pass - def process(self, token_): - auth_in_db(username=sys.argv[2], - password=sys.argv[3]) + @staticmethod + def process(token_): + auth_in_db(username=sys.argv[2], password=sys.argv[3]) if token_ == 'bot': main(sys.argv[1], sys.argv[4]) else: diff --git a/db.py b/db.py index 064236a..4d31770 100644 --- a/db.py +++ b/db.py @@ -3,10 +3,9 @@ from typing import List import pytz -from pymodm import connect, fields, MongoModel, files +from pymodm import connect, fields, MongoModel from pymodm.connection import _get_db import gridfs -from bson import json_util def get_datetime_with_tz(date: datetime.date, time: datetime.time): @@ -82,7 +81,18 @@ class SurveyProgress(MongoModel): stats = fields.CharField() def __str__(self): - return f'{self.user=} | {self.survey_id=} | {self.survey_step=} | {self.survey_next=} | {self.need_answer=} | {self.user_answer=} | {self.stats=} | {self.audio_file=} | {self.time_send_question=}, {self.time_receive_answer=}' + return ( + f'{self.user=} | ' + f'{self.survey_id=} | ' + f'{self.survey_step=} | ' + f'{self.survey_next=} | ' + f'{self.need_answer=} | ' + f'{self.user_answer=} | ' + f'{self.stats=} | ' + f'{self.audio_file=} | ' + f'{self.time_send_question=}, ' + f'{self.time_receive_answer=}' + ) class Survey(MongoModel): @@ -99,34 +109,54 @@ class BotAudioAnswer(MongoModel): audio_answer = fields.FileField() text_of_audio_answer = fields.CharField() time_send_answer = fields.DateTimeField() - + def __str__(self) -> str: - return f'{self.id=} | {self.audio_answer=} | {self.text_of_audio_answer=} | {self.time_send_answer=}' - - + return ( + f'{self.id=} | ' + f'{self.audio_answer=} | ' + f'{self.text_of_audio_answer=} | ' + f'{self.time_send_answer=}' + ) + + def init_user(user) -> User: try: return User.objects.get({'id': user.id}) except User.DoesNotExist: - return User(id=user.id, - first_name=user.first_name, - is_bot=user.is_bot, - username=user.username, - language_code=user.language_code).save() - - -def init_survey_progress(user, focus, id=0, survey_step=0, next_step=1, need_answer=False, user_answer="INIT PROGRESS", stats="", audio_file=None) -> SurveyProgress: + return User( + id=user.id, + first_name=user.first_name, + is_bot=user.is_bot, + username=user.username, + language_code=user.language_code + ).save() + + +def init_survey_progress( + user, + focus, + id_=0, + survey_step=0, + next_step=1, + need_answer=False, + user_answer="INIT PROGRESS", + stats="", + audio_file=None +) -> SurveyProgress: date = pytz.utc.localize(datetime.datetime.utcnow()) - return SurveyProgress(id=id, user=user, - survey_id=focus, - survey_step=survey_step, - survey_next=survey_step + 1, - need_answer=need_answer, - user_answer=user_answer, - audio_file=audio_file, - stats=stats, - time_send_question=date, - time_receive_answer=date) + return SurveyProgress( + id=id_, + user=user, + survey_id=focus, + survey_step=survey_step, + survey_next=survey_step + 1, + need_answer=need_answer, + user_answer=user_answer, + audio_file=audio_file, + stats=stats, + time_send_question=date, + time_receive_answer=date + ) def get_user_answer(user, focus, step) -> str: @@ -134,6 +164,7 @@ def get_user_answer(user, focus, step) -> str: for survey_step in list_survey_progress.reverse(): if survey_step.user.id == user.id and survey_step.survey_step == step: return survey_step.user_answer + return '' def get_survey_progress(user, focus) -> SurveyProgress: @@ -171,10 +202,12 @@ def push_user_schedule(user, schedule, date): if schedule == DEBUG: is_test = True db_user = init_user(user) - Schedule(user=db_user, - time_to_ask=TIME_VALUES[schedule], - is_test=is_test, - is_on=True).save() + Schedule( + user=db_user, + time_to_ask=TIME_VALUES[schedule], + is_test=is_test, + is_on=True + ).save() def push_user_focus(user, focus, date): @@ -188,48 +221,67 @@ def push_user_feeling(user, feeling, date): db_user.feelings.append({'feel': feeling, 'date': date}) db_user.save() -def push_user_survey_progress(user, focus, id=0, survey_step=0, next_step=1, need_answer=False, user_answer="INIT PROGRESS", stats="", audio_file=None): + +def push_user_survey_progress( + user, + focus, + id_=0, + survey_step=0, + _=1, + need_answer=False, + user_answer="INIT PROGRESS", + stats="", + audio_file=None +): date = pytz.utc.localize(datetime.datetime.utcnow()) db_user = init_user(user) - SurveyProgress(id=id, - user=db_user, - survey_id=focus, - survey_step=survey_step, - survey_next=survey_step + 1, - need_answer=need_answer, - user_answer=user_answer, - audio_file=audio_file, - stats=stats, - time_send_question=date, - time_receive_answer=date).save() - -def push_bot_answer(id=0, answer=None, text=""): + SurveyProgress( + id=id_, + user=db_user, + survey_id=focus, + survey_step=survey_step, + survey_next=survey_step + 1, + need_answer=need_answer, + user_answer=user_answer, + audio_file=audio_file, + stats=stats, + time_send_question=date, + time_receive_answer=date + ).save() + + +def push_bot_answer(id_=0, answer=None, text=""): date = pytz.utc.localize(datetime.datetime.utcnow()) - BotAudioAnswer(id=id, - audio_answer = answer, - text_of_audio_answer = text, - time_send_answer=date).save() - + BotAudioAnswer( + id=id_, + audio_answer=answer, + text_of_audio_answer=text, + time_send_answer=date + ).save() + + def get_user_feelings(user): db_user = init_user(user) return f"Вы сообщали о своем состоянии {len(list(db_user.feelings))} раз" + def get_user_audio(user): - db_user = init_user(user) progress = list(SurveyProgress.objects.values().all()) - fs = gridfs.GridFSBucket(_get_db()) - audio_file = fs.open_download_stream(progress[-1]["audio_file"])._id - #print(audio_file) - #audio_id = fs.find({"filename": 'audio_file'}, no_cursor_timeout=True).distinct('_id') - #print(json.loads(json_util.dumps(audio_id))) + file_storage = gridfs.GridFSBucket(_get_db()) + audio_file = file_storage.open_download_stream(progress[-1]["audio_file"])._id + # print(audio_file) + # audio_id = file_storage.find({"filename": 'audio_file'}, no_cursor_timeout=True).distinct('_id') + # print(json.loads(json_util.dumps(audio_id))) return audio_file - + + def get_bot_audio(): answer = list(BotAudioAnswer.objects.values().all()) - fs = gridfs.GridFSBucket(_get_db()) - bot_audio = fs.open_download_stream(answer[-1]["audio_answer"]).read() + file_storage = gridfs.GridFSBucket(_get_db()) + bot_audio = file_storage.open_download_stream(answer[-1]["audio_answer"]).read() return bot_audio + def set_user_ready_flag(user, flag): db_user = init_user(user) db_user.ready_flag = flag @@ -267,7 +319,8 @@ def get_users_not_finish_survey(): last_focus = user.focuses[-1]['focus'] survey_progress = get_survey_progress(user, last_focus) if survey_progress.need_answer: - list_survey_progress = SurveyProgress.objects.raw({'survey_id': last_focus}) + list_survey_progress = SurveyProgress.objects.raw( + {'survey_id': last_focus}) for i in list_survey_progress: if i.user.id == user.id and i.survey_step == 0: start_time = i.time_send_question @@ -292,7 +345,8 @@ def set_last_usage(user): def get_users_not_answer_last24hours(): users = [] for user in User.objects.all(): - if user.last_usage==None or pytz.utc.localize(user.last_usage) < pytz.utc.localize(datetime.datetime.utcnow()) - datetime.timedelta(days=1): + if user.last_usage is None or pytz.utc.localize(user.last_usage) < pytz.utc.localize( + datetime.datetime.utcnow()) - datetime.timedelta(days=1): users.append({ 'id': user.id, 'username': user.username @@ -301,4 +355,6 @@ def get_users_not_answer_last24hours(): def auth_in_db(username, password): - connect(f'mongodb://{username}:{password}@db:27017/{DATABASE_NAME}?authSource=admin') + connect( + f'mongodb://{username}:{password}@db:27017/{DATABASE_NAME}?authSource=admin' + ) diff --git a/emotional_speech_recognizing/main.py b/emotional_speech_recognizing/main.py index a2a3ff4..d9bcce7 100644 --- a/emotional_speech_recognizing/main.py +++ b/emotional_speech_recognizing/main.py @@ -1,20 +1,17 @@ import os +import time import numpy as np + import librosa from sklearn.model_selection import train_test_split -from tensorflow.keras.models import Sequential -from tensorflow.keras.layers import Dense, Dropout -#from tensorflow.keras.optimizers import Adam -from tensorflow.keras.callbacks import EarlyStopping -#from sklearn.preprocessing import LabelEncoder -#from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten -#from tensorflow.keras.layers import LSTM -import time +from keras.models import Sequential +from keras.layers import Dense +from keras.callbacks import EarlyStopping start_time = time.time() # Путь к папке с датасетом -dataset_dir = r'AudioData' +DATASET_DIR = r'AudioData' # Список эмоций и соответствующих меток emotions = {'a': 0, 'd': 1, 'f': 2, 'h': 3, 'n': 4, 'sa': 5, 'su': 6} @@ -26,7 +23,7 @@ # Проход по каждой эмоции в папке датасета for emotion in emotions.keys(): # Путь к папке с эмоцией - emotion_dir = os.path.join(dataset_dir, emotion) + emotion_dir = os.path.join(DATASET_DIR, emotion) # Проход по каждому аудиофайлу в папке с эмоцией for file in os.listdir(emotion_dir): @@ -50,15 +47,15 @@ # Создание модели нейронной сети model = Sequential() model.add(Dense(100, activation='relu', input_shape=(X_train.shape[1],))) -#model.add(Dropout(0.5)) +# model.add(Dropout(0.5)) model.add(Dense(100, activation='relu')) -#model.add(Dense(15, activation='relu')) -#model.add(Dense(120, activation='relu')) -#model.add(Dropout(0.5)) +# model.add(Dense(15, activation='relu')) +# model.add(Dense(120, activation='relu')) +# model.add(Dropout(0.5)) model.add(Dense(len(emotions), activation='softmax')) # Компиляция модели -#model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['accuracy']) +# model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['accuracy']) model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # Обучение модели diff --git a/keyboard.py b/keyboard.py index 487eec4..aa3d6bb 100644 --- a/keyboard.py +++ b/keyboard.py @@ -26,7 +26,7 @@ 'r_yes': "Да", 'r_no': "Нет", 'r_1h': "Ответить через час", - + 'menu_change_focus': "Сменить фокус", 'menu_share_event': "Поделиться событием", 'menu_help': "Справка" @@ -94,4 +94,4 @@ def menu_kyeboard() -> ReplyKeyboardMarkup: [VALUES['menu_change_focus']], [VALUES['menu_help']] ] - return ReplyKeyboardMarkup(keyboard, one_time_keyboard=True, resize_keyboard=True) \ No newline at end of file + return ReplyKeyboardMarkup(keyboard, one_time_keyboard=True, resize_keyboard=True) diff --git a/my_cron.py b/my_cron.py index 91893de..0613d52 100644 --- a/my_cron.py +++ b/my_cron.py @@ -9,7 +9,6 @@ from bot import ask_ready, resume_survey from db import get_schedule_list_for_feeling_ask, Schedule, get_users_not_finish_survey -from logs import init_logger MINUTES_FOR_LOOP = 1 diff --git a/requirements.txt b/requirements.txt index c2726e5..a1ee68a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,4 +24,6 @@ pymongo==3.11.3 pymodm==0.4.3 cPython==0.0.6 noisereduce==2.0.1 -requests==2.30.0 \ No newline at end of file +requests==2.30.0 +torchaudio==2.0.2 +whisper==1.1.10 \ No newline at end of file diff --git a/script_engine.py b/script_engine.py index 796f6f5..3aff8ef 100644 --- a/script_engine.py +++ b/script_engine.py @@ -1,8 +1,8 @@ import copy import json -import logging -import pytz import datetime + +import pytz from telegram import Update from telegram.ext import CallbackContext from db import init_user, get_survey_progress, init_survey_progress, get_user_answer @@ -32,7 +32,9 @@ class Step: # класс для работы с текущим шагом def __init__(self, update, survey_progress, focus): self.update = update self.survey_progress = survey_progress - self.step_info = Script(Parser("tree_example.json").parse()).get_script(focus)[survey_progress.survey_step] + self.step_info = Script( + Parser("tree_example.json").parse()).get_script(focus)[ + survey_progress.survey_step] def processing_options(self): next_step = None @@ -40,22 +42,26 @@ def processing_options(self): if option['type'] == 'send_message': self.update.effective_user.send_message(text=option['text'], ) elif option['type'] == 'get_user_answer': - answer = get_user_answer(init_user(self.update.effective_user), self.step_info['script_name'], - option['step']) + answer = get_user_answer( + init_user( + self.update.effective_user), + self.step_info['script_name'], + option['step']) self.update.effective_user.send_message(answer) elif option['type'] == 'inline_keyboard': - self.update.effective_user.send_message(text=option['text'], - reply_markup=yes_no_keyboard()) + self.update.effective_user.send_message( + text=option['text'], reply_markup=yes_no_keyboard()) elif option['type'] == 'inline_answer' and self.update.callback_query is not None: if option['answer'] == self.update.callback_query.data: if option['message']['type'] == 'text': - self.update.effective_user.send_message(text=option["message"]["text"]) + self.update.effective_user.send_message( + text=option["message"]["text"]) elif option['message']['type'] == 'voice': with open(option["message"]["source"], 'rb') as stream: self.update.effective_user.send_voice(voice=stream) elif option['message']['type'] == 'inline_keyboard': - self.update.effective_user.send_message(text=option["message"]["text"], - reply_markup=yes_no_keyboard()) + self.update.effective_user.send_message( + text=option["message"]["text"], reply_markup=yes_no_keyboard()) next_step = option['next'] elif option['type'] == 'send_voice': @@ -64,10 +70,11 @@ def processing_options(self): return next_step def execute(self) -> str: - next = self.processing_options() - if next is not None: - self.survey_progress.survey_next = next - self.survey_progress.time_send_question = pytz.utc.localize(datetime.datetime.utcnow()) + survey_next = self.processing_options() + if survey_next is not None: + self.survey_progress.survey_next = survey_next + self.survey_progress.time_send_question = pytz.utc.localize( + datetime.datetime.utcnow()) self.survey_progress.need_answer = self.step_info['need_answer'] self.survey_progress.save() return self.step_info['state'] @@ -85,8 +92,12 @@ def get_next_step(self) -> Step: step_number = self.survey_progress.survey_step if self.update.callback_query is not None: self.update.callback_query.delete_message() - if self.survey_progress.need_answer == True and self.survey_progress.user_answer == "INIT PROGRESS" and \ - self.survey_progress.time_send_question+datetime.timedelta(days=0, seconds=7200) < datetime.datetime.utcnow(): + if ( + self.survey_progress.need_answer and + self.survey_progress.user_answer == "INIT PROGRESS" and + self.survey_progress.time_send_question + + datetime.timedelta(hours=2) < datetime.datetime.utcnow() + ): step = Step(self.update, self.survey_progress, self.last_focus) if self.update.callback_query is not None: query = self.update.callback_query @@ -111,7 +122,14 @@ def get_next_step(self) -> Step: self.survey_progress.save() step_number = self.survey_progress.survey_next # Генерация нового - new_step_info = Script(Parser("tree_example.json").parse()).get_script(self.last_focus)[step_number] - new_survey_progress = init_survey_progress(self.user, self.last_focus, self.update.update_id, step_number, new_step_info['next']) + new_step_info = Script( + Parser("tree_example.json").parse()).get_script( + self.last_focus)[step_number] + new_survey_progress = init_survey_progress( + self.user, + self.last_focus, + self.update.update_id, + step_number, + new_step_info['next']) next_step = Step(self.update, new_survey_progress, self.last_focus) return next_step diff --git a/silero_demo/bot.py b/silero_demo/bot.py index de4860f..f0c4c23 100644 --- a/silero_demo/bot.py +++ b/silero_demo/bot.py @@ -1,5 +1,4 @@ import sys -import os from telegram import Update from telegram.ext import ( @@ -10,20 +9,24 @@ CallbackContext, ) -from silero_test import * +from silero_test import silero_test + + def start_callback(update: Update, context: CallbackContext) -> None: msg = "Отправь мне сообщение" update.message.reply_text(msg) + def send_audio_answer_text(update: Update, context: CallbackContext): audio = silero_test(handle_text(update, context)) - with open(audio, 'rb') as f: - update.effective_user.send_audio(f) + with open(audio, 'rb') as file_: + update.effective_user.send_audio(file_) + def send_audio_answer_voice(update: Update, context: CallbackContext): audio = silero_test() - with open(audio, 'rb') as f: - update.effective_user.send_audio(f) + with open(audio, 'rb') as file_: + update.effective_user.send_audio(file_) def handle_text(update: Update, context: CallbackContext): @@ -49,7 +52,6 @@ def main(token, mode): elif mode == 'voice': dispatcher.add_handler(MessageHandler(Filters.voice, send_audio_answer_voice)) - # Start the Bot updater.start_polling() @@ -61,4 +63,4 @@ def main(token, mode): if __name__ == '__main__': main(sys.argv[1], sys.argv[2]) - # main(config.BOT_TOKEN) \ No newline at end of file + # main(config.BOT_TOKEN) diff --git a/silero_demo/silero_test.py b/silero_demo/silero_test.py index b4e54c5..789692c 100644 --- a/silero_demo/silero_test.py +++ b/silero_demo/silero_test.py @@ -1,15 +1,15 @@ +import re + import torch -import time -import sounddevice as sd import torchaudio -import re -language = 'ru' -model_id = 'v3_1_ru' -sample_rate = 48000 -speaker = 'baya' -device = torch.device('cpu') -example_text = "Привет. я бот-психолог" +LANGUAGE = 'ru' +MODEL_ID = 'v3_1_ru' +SAMPLE_RATE = 48000 +SPEAKER = 'baya' +DEVICE = torch.device('cpu') +EXAMPLE_TEXT = "Привет. я бот-психолог" + def add_intonation(text, words, intonation_parameters): text = text.lower() @@ -26,22 +26,30 @@ def reformat_text(text): text = "" + '\n'.join(paragraphs) + "" return text -def silero_test(text=example_text): - model, _ = torch.hub.load(repo_or_dir='snakers4/silero-models', - model='silero_tts', - language=language, - speaker=model_id) - model.to(device) # gpu or cpu + +def silero_test(text=EXAMPLE_TEXT): + model, _ = torch.hub.load( + repo_or_dir='snakers4/silero-models', + model='silero_tts', + language=LANGUAGE, + speaker=MODEL_ID + ) + + model.to(DEVICE) # gpu or cpu text = reformat_text(text) text = add_intonation(text, ["привет"], ['prosody', 'pitch="x-high" rate="x-slow"']) text = add_intonation(text, ["пока"], ['prosody', 'pitch="x-low" rate="x-fast"']) - audio = model.apply_tts(ssml_text=text, - speaker=speaker, - sample_rate=sample_rate) + audio = model.apply_tts( + ssml_text=text, + speaker=SPEAKER, + sample_rate=SAMPLE_RATE + ) filename = 'test_1.wav' - torchaudio.save(filename, - audio.unsqueeze(0), - sample_rate=sample_rate) + torchaudio.save( + filename, + audio.unsqueeze(0), + sample_rate=SAMPLE_RATE + ) return filename diff --git a/silero_module.py b/silero_module.py index 8844d2c..2c65def 100644 --- a/silero_module.py +++ b/silero_module.py @@ -1,6 +1,5 @@ import os import requests -import time class VoiceSettings: diff --git a/test_script_engine.py b/test_script_engine.py index 7285c7d..2c4d5e4 100644 --- a/test_script_engine.py +++ b/test_script_engine.py @@ -2,35 +2,103 @@ from unittest import mock from json.decoder import JSONDecodeError import sys -from telegram import Update -import pytz -import datetime -from db import User, SurveyProgress, init_user, init_survey_progress -from script_engine import Script, Parser, Step from pymodm import connect +from db import User, init_user, init_survey_progress +from script_engine import Script, Parser, Step + class TestScript(unittest.TestCase): def test_get_script(self): - self.assertEqual(Script({'f_tired': {'script_body': [{'script_name': 'f_tired', 'options': - [{'type': 'send_message', 'text': 'message'}]}, {'script_name': 'f_tired', - 'id': 'tired_0.1'}]}}).get_script('f_tired'), [ - {'script_name': 'f_tired', 'options': [{'type': 'send_message', 'text': 'message'}]}, - {'script_name': 'f_tired', 'id': 'tired_0.1'}]) - self.assertRaises(KeyError, Script({'f_tired': {'script_body': [{'script_name': 'f_tired', 'options': - [{'type': 'send_message', 'text': 'message'}]}, {'script_name': 'f_tired', - 'id': 'tired_0.1'}]}}).get_script('ff_tired')) + self.assertEqual( + Script( + { + 'f_tired': { + 'script_body': [ + { + 'script_name': 'f_tired', + 'options': [ + { + 'type': 'send_message', + 'text': 'message' + } + ] + }, + { + 'script_name': 'f_tired', + 'id': 'tired_0.1' + } + ] + } + } + ).get_script('f_tired'), + [ + { + 'script_name': 'f_tired', + 'options': [ + { + 'type': 'send_message', + 'text': 'message' + } + ] + }, { + 'script_name': 'f_tired', + 'id': 'tired_0.1' + } + ] + ) + self.assertRaises( + KeyError, + Script( + { + 'f_tired': { + 'script_body': [ + { + 'script_name': 'f_tired', + 'options': [ + { + 'type': 'send_message', + 'text': 'message' + } + ] + }, + { + 'script_name': 'f_tired', + 'id': 'tired_0.1' + } + ] + } + } + ).get_script('ff_tired')) class TestParser(unittest.TestCase): def test_parse(self): - self.assertEqual(Parser("test_tree.json").parse(), - {'f_tired': {'script_body': [{'script_name': 'f_tired', 'options': - [{'type': 'send_message', 'text': 'message'}]}, - {'script_name': 'f_tired', 'id': 'tired_0.1'}]}}) + self.assertEqual( + Parser("test_tree.json").parse(), + { + 'f_tired': { + 'script_body': [ + { + 'script_name': 'f_tired', + 'options': [ + { + 'type': 'send_message', + 'text': 'message' + } + ] + }, + { + 'script_name': 'f_tired', + 'id': 'tired_0.1' + } + ] + } + } + ) self.assertRaises(FileNotFoundError, Parser("test_treee.json").parse()) self.assertRaises(JSONDecodeError, Parser("test_broken_tree.json").parse()) @@ -39,22 +107,23 @@ class TestStep(unittest.TestCase): @mock.patch('telegram.Update') @mock.patch('telegram.User') - def test_processing_options(self, MockUser, MockUpdate): - update = MockUpdate() - update.effective_user = MockUser() + def test_processing_options(self, mock_user, mock_update): + update = mock_update() + update.effective_user = mock_user() update.effective_user.send_message.return_value = [] update.callback_query.data = 'r_yes' user = init_user(User(**{'id': 681004065})) focus = 'f_self-doubt' - survey_progress = init_survey_progress(user, focus=focus, survey_step=4) + survey_progress = init_survey_progress( + user, focus=focus, survey_step=4) step = Step(update, survey_progress, focus) self.assertEqual(step.processing_options(), 3) @mock.patch('telegram.Update') @mock.patch('telegram.User') - def test_execute(self, MockUser, MockUpdate): - update = MockUpdate() - update.effective_user = MockUser() + def test_execute(self, mock_user, mock_update): + update = mock_update() + update.effective_user = mock_user() update.effective_user.send_message.return_value = [] user = init_user(User(**{'id': 681004065})) focus = 'f_tired' @@ -64,7 +133,7 @@ def test_execute(self, MockUser, MockUpdate): if __name__ == '__main__': - db_address = sys.argv[1] + db_address = sys.argv[1] # pylint: disable=invalid-name connect(db_address) res = unittest.main(argv=['first-arg-is-ignored'], exit=False) sys.exit(int(not res.result.wasSuccessful())) diff --git a/voice_module.py b/voice_module.py index 085289a..a0cceb5 100644 --- a/voice_module.py +++ b/voice_module.py @@ -1,7 +1,6 @@ import json import os import subprocess -import wave from noisereduce import reduce_noise from scipy.io import wavfile @@ -34,8 +33,9 @@ def download_voice(update: Update): ogg_filename += f"/{downloaded_file.file_unique_id}.ogg" with open(ogg_filename, "wb") as voice_file: voice_file.write(voice_bytearray) - wav_filename = ogg_filename.split(".")[0]+".wav" - command = f"ffmpeg -i {ogg_filename} -ar 16000 -ac 1 -ab 256K -f wav {wav_filename}" #16000 - частота дискретизации, 1 - кол-во аудиоканалов, 256К - битрейт + wav_filename = ogg_filename.split(".")[0] + ".wav" + # 16000 - частота дискретизации, 1 - кол-во аудиоканалов, 256К - битрейт + command = f"ffmpeg -i {ogg_filename} -ar 16000 -ac 1 -ab 256K -f wav {wav_filename}" subprocess.run(command.split()) return (wav_filename, ogg_filename) @@ -58,8 +58,18 @@ def work_with_audio(update: Update, context: CallbackContext): update.effective_user.send_message(input_sentence.generate_output_info()) elif debug == "false": pass - push_user_survey_progress(update.effective_user, init_user(update.effective_user).focuses[-1]['focus'], update.update_id, user_answer=input_sentence._text, stats=stats_sentence, audio_file=open(ogg_filename, 'rb')) + push_user_survey_progress( + update.effective_user, + init_user(update.effective_user).focuses[-1]['focus'], + update.update_id, + user_answer=input_sentence._text, + stats=stats_sentence, + audio_file=open(ogg_filename, 'rb') # pylint: disable=consider-using-with + ) os.remove(ogg_filename) if debug == "true": print(get_user_audio(update.effective_user)) - update.effective_user.send_message("ID записи с твоим аудиосообщением в базе данных: " + str(json.loads(json_util.dumps(get_user_audio(update.effective_user))))) + update.effective_user.send_message( + "ID записи с твоим аудиосообщением в базе данных: " + str( + json.loads(json_util.dumps(get_user_audio(update.effective_user)))) + ) From b59f157264014f985cbdc1facaafb5b8838cdc4b Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Tue, 25 Jul 2023 10:44:19 +0300 Subject: [PATCH 5/7] fix yaml --- .github/workflows/linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index ac5d02b..455ba54 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,6 +1,6 @@ name: PEP8 Style Guide Enforcement -on: [push, pull_request] +on: [push] jobs: build: From 29c3fb44ab72c5ec16c1ec6c6fef1c32deb5d4fd Mon Sep 17 00:00:00 2001 From: thehighestmath Date: Tue, 25 Jul 2023 10:39:18 +0300 Subject: [PATCH 6/7] apply black style --- TestPayment/pay_bot.py | 4 +- audio_classes.py | 7 ++- bot.py | 42 +++++++------- db.py | 83 +++++++++++++--------------- emotional_speech_recognizing/main.py | 9 ++- install_all_requirements.sh | 12 ++++ keyboard.py | 29 +++------- run_black.sh | 3 + run_pylint.sh | 3 + run_unittests.sh | 0 script_engine.py | 47 ++++++++-------- silero_demo/bot.py | 8 +-- silero_demo/silero_test.py | 18 ++---- silero_module.py | 1 - test_script_engine.py | 64 +++++---------------- voice_module.py | 8 +-- 16 files changed, 151 insertions(+), 187 deletions(-) create mode 100755 install_all_requirements.sh create mode 100755 run_black.sh create mode 100755 run_pylint.sh mode change 100644 => 100755 run_unittests.sh diff --git a/TestPayment/pay_bot.py b/TestPayment/pay_bot.py index a8a215c..7a7804a 100644 --- a/TestPayment/pay_bot.py +++ b/TestPayment/pay_bot.py @@ -48,7 +48,9 @@ def start_without_shipping_callback(update: Update, context: CallbackContext) -> # optionally pass need_name=True, need_phone_number=True, # need_email=True, need_shipping_address=True, is_flexible=True - context.bot.send_invoice(chat_id, title, description, payload, provider_token, start_parameter, currency, prices) + context.bot.send_invoice( + chat_id, title, description, payload, provider_token, start_parameter, currency, prices + ) # after (optional) shipping, it's the pre-checkout diff --git a/audio_classes.py b/audio_classes.py index 4b248c6..6f89d83 100644 --- a/audio_classes.py +++ b/audio_classes.py @@ -30,4 +30,9 @@ def generate_output_info(self): return "".join(answer_list) def generate_stats(self): - return '\n'.join([f"{i.word} - {i.begin_timestamp} - {i.end_timestamp} - {i.probability}" for i in self._words]) + return '\n'.join( + [ + f"{i.word} - {i.begin_timestamp} - {i.end_timestamp} - {i.probability}" + for i in self._words + ] + ) diff --git a/bot.py b/bot.py index 6a23be9..f586919 100644 --- a/bot.py +++ b/bot.py @@ -24,7 +24,8 @@ set_schedule_asked_today, init_user, get_schedule_by_user, - auth_in_db, set_last_usage, + auth_in_db, + set_last_usage, get_users_not_answer_last24hours, get_users_not_finish_survey, ) @@ -56,11 +57,10 @@ def start(update: Update, context: CallbackContext) -> str: update.message.reply_text( 'Привет! Я бот, который поможет тебе отрефлексировать твое настроение', - reply_markup=menu_kyeboard() + reply_markup=menu_kyeboard(), ) update.message.reply_text( - 'В какое время тебе удобно подводить итоги дня?', - reply_markup=daily_schedule_keyboard() + 'В какое время тебе удобно подводить итоги дня?', reply_markup=daily_schedule_keyboard() ) @@ -68,7 +68,7 @@ def ask_focus(update: Update) -> None: update.effective_user.send_message( 'Подведение итогов дня поможет исследовать определенные сложности и паттерны твоего поведения. ' 'Каждую неделю можно выбирать разные фокусы или один и тот же. Выбрать фокус этой недели:', - reply_markup=focus_keyboard() + reply_markup=focus_keyboard(), ) @@ -94,10 +94,8 @@ def button(update: Update, context: CallbackContext) -> str: return engine_callback(update, context) elif query.data.startswith('r_') and ( - last_message in [ - 'Привет! Пришло время подводить итоги. Давай?', - 'Продолжить прохождение опроса?' - ] + last_message + in ['Привет! Пришло время подводить итоги. Давай?', 'Продолжить прохождение опроса?'] ): if query.data == 'r_yes': return engine_callback(update, context) @@ -168,7 +166,7 @@ def ask_ready(updater, schedule): updater.bot.send_message( schedule.user.id, "Привет! Пришло время подводить итоги. Давай?", - reply_markup=ready_keyboard() + reply_markup=ready_keyboard(), ) @@ -177,7 +175,9 @@ def resume_survey(updater, user) -> None: def ask_feelings(update: Update, context: CallbackContext) -> None: - update.effective_user.send_message("Расскажи, как прошел твой день?", reply_markup=mood_keyboard()) + update.effective_user.send_message( + "Расскажи, как прошел твой день?", reply_markup=mood_keyboard() + ) # def engine_callback(update, context: CallbackContext) -> int: @@ -197,14 +197,10 @@ def cancel(update: Update, context: CallbackContext): def change_focus(update: Update, context: CallbackContext): user = init_user(update.effective_user) set_last_usage(user) - update.effective_user.send_message( - 'Выберете новый фокус:', - reply_markup=focus_keyboard() - ) + update.effective_user.send_message('Выберете новый фокус:', reply_markup=focus_keyboard()) def send_audio_answer(update: Update, context: CallbackContext): - update.effective_user.send_message("Уже обрабатываю твоё сообщение") text = update.message.text # 'Спасибо, что поделился своими переживаниями' @@ -231,12 +227,20 @@ def main(token, mode): updater.dispatcher.add_handler(CommandHandler('user_help', user_help)) updater.dispatcher.add_handler(CommandHandler('stats', stats)) updater.dispatcher.add_handler(CommandHandler('change_focus', change_focus)) - updater.dispatcher.add_handler(CommandHandler('get_users_not_finish_survey', debug_get_users_not_finish_survey)) - updater.dispatcher.add_handler(CommandHandler('get_users_not_answer_last24hours', debug_get_users_not_answer_last24hours)) + updater.dispatcher.add_handler( + CommandHandler('get_users_not_finish_survey', debug_get_users_not_finish_survey) + ) + updater.dispatcher.add_handler( + CommandHandler( + 'get_users_not_answer_last24hours', debug_get_users_not_answer_last24hours + ) + ) updater.dispatcher.add_handler(CommandHandler('cancel', cancel)) updater.dispatcher.add_handler(CallbackQueryHandler(button)) - updater.dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, text_processing)) + updater.dispatcher.add_handler( + MessageHandler(Filters.text & ~Filters.command, text_processing) + ) updater.start_polling() # updater.idle() diff --git a/db.py b/db.py index 4d31770..3ad6e63 100644 --- a/db.py +++ b/db.py @@ -25,7 +25,7 @@ def get_datetime_with_tz(date: datetime.date, time: datetime.time): 's_22': get_datetime_with_tz(START_UNIX, datetime.time(hour=22 - 3)), 's_23': get_datetime_with_tz(START_UNIX, datetime.time(hour=23 - 3)), # TODO: --------------- - DEBUG: get_datetime_with_tz(START_UNIX, datetime.datetime.utcnow().time()) + DEBUG: get_datetime_with_tz(START_UNIX, datetime.datetime.utcnow().time()), } @@ -128,7 +128,7 @@ def init_user(user) -> User: first_name=user.first_name, is_bot=user.is_bot, username=user.username, - language_code=user.language_code + language_code=user.language_code, ).save() @@ -141,7 +141,7 @@ def init_survey_progress( need_answer=False, user_answer="INIT PROGRESS", stats="", - audio_file=None + audio_file=None, ) -> SurveyProgress: date = pytz.utc.localize(datetime.datetime.utcnow()) return SurveyProgress( @@ -155,7 +155,7 @@ def init_survey_progress( audio_file=audio_file, stats=stats, time_send_question=date, - time_receive_answer=date + time_receive_answer=date, ) @@ -180,10 +180,14 @@ def get_survey_progress(user, focus) -> SurveyProgress: def get_schedule_by_user(user, is_test=True): logger = logging.getLogger(__name__) - schedules: List[Schedule] = list(Schedule.objects.raw({ - # 'user': {'$elemMatch': {'id': user.id}}, - 'is_test': is_test - })) + schedules: List[Schedule] = list( + Schedule.objects.raw( + { + # 'user': {'$elemMatch': {'id': user.id}}, + 'is_test': is_test + } + ) + ) filter_schedules = [] for schedule in schedules: if schedule.user.id == user.id: @@ -202,12 +206,7 @@ def push_user_schedule(user, schedule, date): if schedule == DEBUG: is_test = True db_user = init_user(user) - Schedule( - user=db_user, - time_to_ask=TIME_VALUES[schedule], - is_test=is_test, - is_on=True - ).save() + Schedule(user=db_user, time_to_ask=TIME_VALUES[schedule], is_test=is_test, is_on=True).save() def push_user_focus(user, focus, date): @@ -231,7 +230,7 @@ def push_user_survey_progress( need_answer=False, user_answer="INIT PROGRESS", stats="", - audio_file=None + audio_file=None, ): date = pytz.utc.localize(datetime.datetime.utcnow()) db_user = init_user(user) @@ -246,17 +245,14 @@ def push_user_survey_progress( audio_file=audio_file, stats=stats, time_send_question=date, - time_receive_answer=date + time_receive_answer=date, ).save() def push_bot_answer(id_=0, answer=None, text=""): date = pytz.utc.localize(datetime.datetime.utcnow()) BotAudioAnswer( - id=id_, - audio_answer=answer, - text_of_audio_answer=text, - time_send_answer=date + id=id_, audio_answer=answer, text_of_audio_answer=text, time_send_answer=date ).save() @@ -294,7 +290,9 @@ def set_schedule_is_on_flag(schedule, flag): def set_schedule_asked_today(schedule): - schedule.sending_list.append({'date': pytz.utc.localize(datetime.datetime.utcnow()), 'success': True}) + schedule.sending_list.append( + {'date': pytz.utc.localize(datetime.datetime.utcnow()), 'success': True} + ) schedule.save() @@ -304,13 +302,9 @@ def get_schedule_list_for_feeling_ask(): today = datetime.datetime(year=1970, month=1, day=1) dt_from = get_datetime_with_tz(today, datetime.time(hour=now.hour)) dt_to = get_datetime_with_tz(today, datetime.time(hour=now.hour)) + datetime.timedelta(hours=1) - return list(Schedule.objects.raw({ - 'time_to_ask': { - '$gte': dt_from, - '$lt': dt_to, - }, - 'is_on': True - })) + return list( + Schedule.objects.raw({'time_to_ask': {'$gte': dt_from, '$lt': dt_to}, 'is_on': True}) + ) def get_users_not_finish_survey(): @@ -319,20 +313,21 @@ def get_users_not_finish_survey(): last_focus = user.focuses[-1]['focus'] survey_progress = get_survey_progress(user, last_focus) if survey_progress.need_answer: - list_survey_progress = SurveyProgress.objects.raw( - {'survey_id': last_focus}) + list_survey_progress = SurveyProgress.objects.raw({'survey_id': last_focus}) for i in list_survey_progress: if i.user.id == user.id and i.survey_step == 0: start_time = i.time_send_question time_not_finish = datetime.datetime.utcnow() - start_time - users.append({ - 'id': user.id, - 'username': user.username, - 'survey_type': last_focus, - 'start_time': start_time, - 'time_not_finish': time_not_finish, - 'survey_step': survey_progress.survey_step, - }) + users.append( + { + 'id': user.id, + 'username': user.username, + 'survey_type': last_focus, + 'start_time': start_time, + 'time_not_finish': time_not_finish, + 'survey_step': survey_progress.survey_step, + } + ) return users @@ -346,15 +341,11 @@ def get_users_not_answer_last24hours(): users = [] for user in User.objects.all(): if user.last_usage is None or pytz.utc.localize(user.last_usage) < pytz.utc.localize( - datetime.datetime.utcnow()) - datetime.timedelta(days=1): - users.append({ - 'id': user.id, - 'username': user.username - }) + datetime.datetime.utcnow() + ) - datetime.timedelta(days=1): + users.append({'id': user.id, 'username': user.username}) return users def auth_in_db(username, password): - connect( - f'mongodb://{username}:{password}@db:27017/{DATABASE_NAME}?authSource=admin' - ) + connect(f'mongodb://{username}:{password}@db:27017/{DATABASE_NAME}?authSource=admin') diff --git a/emotional_speech_recognizing/main.py b/emotional_speech_recognizing/main.py index d9bcce7..b2ac7ca 100644 --- a/emotional_speech_recognizing/main.py +++ b/emotional_speech_recognizing/main.py @@ -60,7 +60,14 @@ # Обучение модели early_stopping = EarlyStopping(monitor='val_loss', patience=10) -model.fit(X_train, y_train, epochs=50, batch_size=1, validation_data=(X_test, y_test), callbacks=[early_stopping]) +model.fit( + X_train, + y_train, + epochs=50, + batch_size=1, + validation_data=(X_test, y_test), + callbacks=[early_stopping], +) # Оценка модели на тестовой выборке loss, accuracy = model.evaluate(X_test, y_test, verbose=0) diff --git a/install_all_requirements.sh b/install_all_requirements.sh new file mode 100755 index 0000000..3ab8969 --- /dev/null +++ b/install_all_requirements.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +# install dependences +pip install -r requirements.txt +pip install -r emotional_speech_recognizing/requirements.txt +pip install -r silero_demo/requirements.txt + +# install pylint (for checking) +pip install pylint + +# install black (for autofix) +pip install black diff --git a/keyboard.py b/keyboard.py index aa3d6bb..69c4ddf 100644 --- a/keyboard.py +++ b/keyboard.py @@ -8,13 +8,11 @@ 's_22': "22:00 - 23:00", 's_23': "23:00 - 24:00", 's_right_now': "Прямо сейчас", - 'm_fun': "Веселый", 'm_sad': "Грустный", 'm_angry': "Злой", 'm_anxious': "Тревожный", 'm_urgent': "Состояние из ряда вон", - 'f_tired': "Усталость", 'f_self-doubt': "Неуверенность в себе", 'f_bad': "Все плохо", @@ -22,14 +20,12 @@ 'f_apathy': "Апатия", 'f_results': "Обычные итоги", 'f_groundhog': "День сурка", - 'r_yes': "Да", 'r_no': "Нет", 'r_1h': "Ответить через час", - 'menu_change_focus': "Сменить фокус", 'menu_share_event': "Поделиться событием", - 'menu_help': "Справка" + 'menu_help': "Справка", } @@ -38,9 +34,7 @@ def init_button(key) -> InlineKeyboardButton: def ready_keyboard() -> InlineKeyboardMarkup: - keyboard = [ - [init_button('r_yes'), init_button('r_1h')] - ] + keyboard = [[init_button('r_yes'), init_button('r_1h')]] return InlineKeyboardMarkup(keyboard) @@ -52,7 +46,7 @@ def daily_schedule_keyboard() -> InlineKeyboardMarkup: [init_button('s_21')], [init_button('s_22')], [init_button('s_23')], - [init_button('s_right_now')] + [init_button('s_right_now')], ] return InlineKeyboardMarkup(keyboard) @@ -61,7 +55,8 @@ def mood_keyboard() -> InlineKeyboardMarkup: keyboard = [ [init_button('m_fun'), init_button('m_sad')], [init_button('m_angry'), init_button('m_anxious')], - [init_button('m_urgent')], ] + [init_button('m_urgent')], + ] return InlineKeyboardMarkup(keyboard) @@ -74,24 +69,16 @@ def focus_keyboard() -> InlineKeyboardMarkup: [init_button('f_lonely')], [init_button('f_apathy')], [init_button('f_results')], - [init_button('f_groundhog')] - + [init_button('f_groundhog')], ] return InlineKeyboardMarkup(keyboard) def yes_no_keyboard() -> InlineKeyboardMarkup: - keyboard = [ - [init_button('r_yes')], - [init_button('r_no')] - ] + keyboard = [[init_button('r_yes')], [init_button('r_no')]] return InlineKeyboardMarkup(keyboard) def menu_kyeboard() -> ReplyKeyboardMarkup: - keyboard = [ - [VALUES['menu_share_event']], - [VALUES['menu_change_focus']], - [VALUES['menu_help']] - ] + keyboard = [[VALUES['menu_share_event']], [VALUES['menu_change_focus']], [VALUES['menu_help']]] return ReplyKeyboardMarkup(keyboard, one_time_keyboard=True, resize_keyboard=True) diff --git a/run_black.sh b/run_black.sh new file mode 100755 index 0000000..d49a30d --- /dev/null +++ b/run_black.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +black --skip-string-normalization --skip-magic-trailing-comma --line-length=100 . diff --git a/run_pylint.sh b/run_pylint.sh new file mode 100755 index 0000000..6bdebe2 --- /dev/null +++ b/run_pylint.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +pylint $(git ls-files '*.py') diff --git a/run_unittests.sh b/run_unittests.sh old mode 100644 new mode 100755 diff --git a/script_engine.py b/script_engine.py index 3aff8ef..6c37422 100644 --- a/script_engine.py +++ b/script_engine.py @@ -32,36 +32,37 @@ class Step: # класс для работы с текущим шагом def __init__(self, update, survey_progress, focus): self.update = update self.survey_progress = survey_progress - self.step_info = Script( - Parser("tree_example.json").parse()).get_script(focus)[ - survey_progress.survey_step] + self.step_info = Script(Parser("tree_example.json").parse()).get_script(focus)[ + survey_progress.survey_step + ] def processing_options(self): next_step = None for option in self.step_info['options']: if option['type'] == 'send_message': - self.update.effective_user.send_message(text=option['text'], ) + self.update.effective_user.send_message(text=option['text']) elif option['type'] == 'get_user_answer': answer = get_user_answer( - init_user( - self.update.effective_user), + init_user(self.update.effective_user), self.step_info['script_name'], - option['step']) + option['step'], + ) self.update.effective_user.send_message(answer) elif option['type'] == 'inline_keyboard': self.update.effective_user.send_message( - text=option['text'], reply_markup=yes_no_keyboard()) + text=option['text'], reply_markup=yes_no_keyboard() + ) elif option['type'] == 'inline_answer' and self.update.callback_query is not None: if option['answer'] == self.update.callback_query.data: if option['message']['type'] == 'text': - self.update.effective_user.send_message( - text=option["message"]["text"]) + self.update.effective_user.send_message(text=option["message"]["text"]) elif option['message']['type'] == 'voice': with open(option["message"]["source"], 'rb') as stream: self.update.effective_user.send_voice(voice=stream) elif option['message']['type'] == 'inline_keyboard': self.update.effective_user.send_message( - text=option["message"]["text"], reply_markup=yes_no_keyboard()) + text=option["message"]["text"], reply_markup=yes_no_keyboard() + ) next_step = option['next'] elif option['type'] == 'send_voice': @@ -73,8 +74,7 @@ def execute(self) -> str: survey_next = self.processing_options() if survey_next is not None: self.survey_progress.survey_next = survey_next - self.survey_progress.time_send_question = pytz.utc.localize( - datetime.datetime.utcnow()) + self.survey_progress.time_send_question = pytz.utc.localize(datetime.datetime.utcnow()) self.survey_progress.need_answer = self.step_info['need_answer'] self.survey_progress.save() return self.step_info['state'] @@ -93,10 +93,10 @@ def get_next_step(self) -> Step: if self.update.callback_query is not None: self.update.callback_query.delete_message() if ( - self.survey_progress.need_answer and - self.survey_progress.user_answer == "INIT PROGRESS" and - self.survey_progress.time_send_question + - datetime.timedelta(hours=2) < datetime.datetime.utcnow() + self.survey_progress.need_answer + and self.survey_progress.user_answer == "INIT PROGRESS" + and self.survey_progress.time_send_question + datetime.timedelta(hours=2) + < datetime.datetime.utcnow() ): step = Step(self.update, self.survey_progress, self.last_focus) if self.update.callback_query is not None: @@ -122,14 +122,11 @@ def get_next_step(self) -> Step: self.survey_progress.save() step_number = self.survey_progress.survey_next # Генерация нового - new_step_info = Script( - Parser("tree_example.json").parse()).get_script( - self.last_focus)[step_number] + new_step_info = Script(Parser("tree_example.json").parse()).get_script(self.last_focus)[ + step_number + ] new_survey_progress = init_survey_progress( - self.user, - self.last_focus, - self.update.update_id, - step_number, - new_step_info['next']) + self.user, self.last_focus, self.update.update_id, step_number, new_step_info['next'] + ) next_step = Step(self.update, new_survey_progress, self.last_focus) return next_step diff --git a/silero_demo/bot.py b/silero_demo/bot.py index f0c4c23..f038d5c 100644 --- a/silero_demo/bot.py +++ b/silero_demo/bot.py @@ -1,13 +1,7 @@ import sys from telegram import Update -from telegram.ext import ( - Updater, - CommandHandler, - MessageHandler, - Filters, - CallbackContext, -) +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext from silero_test import silero_test diff --git a/silero_demo/silero_test.py b/silero_demo/silero_test.py index 789692c..d93a6ea 100644 --- a/silero_demo/silero_test.py +++ b/silero_demo/silero_test.py @@ -14,7 +14,9 @@ def add_intonation(text, words, intonation_parameters): text = text.lower() for word in words: - text = text.replace(word, f"<{' '.join(intonation_parameters)}>" + word + f"") + text = text.replace( + word, f"<{' '.join(intonation_parameters)}>" + word + f"" + ) return text @@ -32,7 +34,7 @@ def silero_test(text=EXAMPLE_TEXT): repo_or_dir='snakers4/silero-models', model='silero_tts', language=LANGUAGE, - speaker=MODEL_ID + speaker=MODEL_ID, ) model.to(DEVICE) # gpu or cpu @@ -41,15 +43,7 @@ def silero_test(text=EXAMPLE_TEXT): text = add_intonation(text, ["привет"], ['prosody', 'pitch="x-high" rate="x-slow"']) text = add_intonation(text, ["пока"], ['prosody', 'pitch="x-low" rate="x-fast"']) - audio = model.apply_tts( - ssml_text=text, - speaker=SPEAKER, - sample_rate=SAMPLE_RATE - ) + audio = model.apply_tts(ssml_text=text, speaker=SPEAKER, sample_rate=SAMPLE_RATE) filename = 'test_1.wav' - torchaudio.save( - filename, - audio.unsqueeze(0), - sample_rate=SAMPLE_RATE - ) + torchaudio.save(filename, audio.unsqueeze(0), sample_rate=SAMPLE_RATE) return filename diff --git a/silero_module.py b/silero_module.py index 2c65def..0713068 100644 --- a/silero_module.py +++ b/silero_module.py @@ -11,7 +11,6 @@ class VoiceSettings: def bot_answer_audio(bot_text): - request_params = {'VOICE': VoiceSettings.speaker, 'INPUT_TEXT': bot_text} try: answer = requests.get(VoiceSettings.link + '/process', params=request_params) diff --git a/test_script_engine.py b/test_script_engine.py index 2c4d5e4..4b1ae45 100644 --- a/test_script_engine.py +++ b/test_script_engine.py @@ -10,7 +10,6 @@ class TestScript(unittest.TestCase): - def test_get_script(self): self.assertEqual( Script( @@ -19,17 +18,9 @@ def test_get_script(self): 'script_body': [ { 'script_name': 'f_tired', - 'options': [ - { - 'type': 'send_message', - 'text': 'message' - } - ] + 'options': [{'type': 'send_message', 'text': 'message'}], }, - { - 'script_name': 'f_tired', - 'id': 'tired_0.1' - } + {'script_name': 'f_tired', 'id': 'tired_0.1'}, ] } } @@ -37,17 +28,10 @@ def test_get_script(self): [ { 'script_name': 'f_tired', - 'options': [ - { - 'type': 'send_message', - 'text': 'message' - } - ] - }, { - 'script_name': 'f_tired', - 'id': 'tired_0.1' - } - ] + 'options': [{'type': 'send_message', 'text': 'message'}], + }, + {'script_name': 'f_tired', 'id': 'tired_0.1'}, + ], ) self.assertRaises( KeyError, @@ -57,25 +41,17 @@ def test_get_script(self): 'script_body': [ { 'script_name': 'f_tired', - 'options': [ - { - 'type': 'send_message', - 'text': 'message' - } - ] + 'options': [{'type': 'send_message', 'text': 'message'}], }, - { - 'script_name': 'f_tired', - 'id': 'tired_0.1' - } + {'script_name': 'f_tired', 'id': 'tired_0.1'}, ] } } - ).get_script('ff_tired')) + ).get_script('ff_tired'), + ) class TestParser(unittest.TestCase): - def test_parse(self): self.assertEqual( Parser("test_tree.json").parse(), @@ -84,27 +60,18 @@ def test_parse(self): 'script_body': [ { 'script_name': 'f_tired', - 'options': [ - { - 'type': 'send_message', - 'text': 'message' - } - ] + 'options': [{'type': 'send_message', 'text': 'message'}], }, - { - 'script_name': 'f_tired', - 'id': 'tired_0.1' - } + {'script_name': 'f_tired', 'id': 'tired_0.1'}, ] } - } + }, ) self.assertRaises(FileNotFoundError, Parser("test_treee.json").parse()) self.assertRaises(JSONDecodeError, Parser("test_broken_tree.json").parse()) class TestStep(unittest.TestCase): - @mock.patch('telegram.Update') @mock.patch('telegram.User') def test_processing_options(self, mock_user, mock_update): @@ -114,8 +81,7 @@ def test_processing_options(self, mock_user, mock_update): update.callback_query.data = 'r_yes' user = init_user(User(**{'id': 681004065})) focus = 'f_self-doubt' - survey_progress = init_survey_progress( - user, focus=focus, survey_step=4) + survey_progress = init_survey_progress(user, focus=focus, survey_step=4) step = Step(update, survey_progress, focus) self.assertEqual(step.processing_options(), 3) @@ -133,7 +99,7 @@ def test_execute(self, mock_user, mock_update): if __name__ == '__main__': - db_address = sys.argv[1] # pylint: disable=invalid-name + db_address = sys.argv[1] # pylint: disable=invalid-name connect(db_address) res = unittest.main(argv=['first-arg-is-ignored'], exit=False) sys.exit(int(not res.result.wasSuccessful())) diff --git a/voice_module.py b/voice_module.py index a0cceb5..e95dd05 100644 --- a/voice_module.py +++ b/voice_module.py @@ -64,12 +64,12 @@ def work_with_audio(update: Update, context: CallbackContext): update.update_id, user_answer=input_sentence._text, stats=stats_sentence, - audio_file=open(ogg_filename, 'rb') # pylint: disable=consider-using-with + audio_file=open(ogg_filename, 'rb'), # pylint: disable=consider-using-with ) os.remove(ogg_filename) if debug == "true": print(get_user_audio(update.effective_user)) update.effective_user.send_message( - "ID записи с твоим аудиосообщением в базе данных: " + str( - json.loads(json_util.dumps(get_user_audio(update.effective_user)))) - ) + "ID записи с твоим аудиосообщением в базе данных: " + + str(json.loads(json_util.dumps(get_user_audio(update.effective_user)))) + ) From 14c2865c9a8e6dccedc059090cd763a47dc7ea70 Mon Sep 17 00:00:00 2001 From: Mark Zaslavskiy Date: Fri, 15 Sep 2023 12:34:07 +0300 Subject: [PATCH 7/7] added versions for docker images --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index e80c002..841fd21 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: "3" services: db: - image: mongo + image: mongo:6.0 restart: unless-stopped env_file: .env volumes: @@ -22,7 +22,7 @@ services: - db silero-tts-service: - image: "navatusein/silero-tts-service" + image: "navatusein/silero-tts-service:1.0.0" container_name: "silero-tts-service" restart: unless-stopped env_file: .env