• Как запускать асинхронную функцию одновременно с поллингом бота телеграмм?

    Vindicar
    @Vindicar
    RTFM!
    start_polling() имеет параметр on_startup, который принимает корутину или список корутин.
    Ответ написан
    Комментировать
  • Не понимаю почему не работает код python, не могли бы пожалуйста объяснить!?

    Vindicar
    @Vindicar
    RTFM!
    при введении пароля выводит ошибку string index out of range и я понимаю что это означает что
    в [] в листе не существующий индекс

    Нет, не понимаешь. Тебе же прямо сказано про строку, а не про список.
    Ты сначала делаешь i = plst[ii], а потом с какого-то перепугу делаешь i[ii].isupper() and not i[ii].isnumeric().
    У тебя i - это уже один символ, так как plst содержит строку, разбитую по символам.
    Ответ написан
    Комментировать
  • Как сделать активацию по спискам?

    Vindicar
    @Vindicar
    RTFM!
    Давай-ка я тебе покажу как я бы эту проблему решил. А уж осилишь или нет...

    Идеи:
    1. Разные команды должны быть независимы друг от друга.
    2. Проверка совпадения текста с командой и выполнение самой команды - разные задачи.
    3. Список команд не должен быть захардкожен.
    4. Код, нужный для реализации и добавления команды, должен быть по возможности сосредоточен в одном месте.
    5. Следует избегать необходимости повторять один и тот же код в обработчиках и предикатах. Это позволит упростить их.

    Следствия:
    1. Каждая команда должна быть отдельной подпрограммой - обработчиком команды.
    2. Для каждого обработчика команды должна существовать отдельная подрограмма - предикат команды. Она проверяет, подходит ли произнесённый текст под команду.
    3. Нужно хранить коллекцию (например, список - list) пар "обработчик - предикат". При работе бот будет перебирать этот список, ища подходящую пару. Должен быть механизм внесения пары в этот список (регистрация обработчика).
    4. Следует предусмотреть возможность регистрации с помощью декораторов. Это удобно и позволяет разместить описание обработчика и его регистрацию рядом, неотрывно друг от друга.
    5а. Основной бот должен заниматься вопросами распознавания речи, проверки наличия ключевого слова (имени бота), вызова предикатов для определения обработчика и возврата ответа пользователю (через консоль или синтез речи).
    5б. Стоит предусмотреть способ автоматического конструирования простых предикатов вроде "текст начинается с указанного слова/слов".

    Отсюда мы получаем следующее...
    Код

    import typing as t
    import speech_recognition as sr
    
    
    # предикат принимает текстовую строку и возвращает истину или ложь
    # истина значит "я понимаю эту строку, мой обработчик с ней справится".
    PredicateFunc = t.Callable[[str], bool]
    # обработчик принимает объект бота и текстовую строку команды. Он не возвращает ничего.
    HandlerFunc = t.Callable[['VoiceBot', str], None]
    
    
    class VoiceBot:
        """Основной класс бота."""
        
        def __init__(self, name: str):
            """Конструктор вызывается при создании экземпляра бота."""
            self._name: str = name.lower()  # любая команда должна начинаться с имени бота
            # список известных боту обработчиков
            self._handlers: t.List[t.Tuple[PredicateFunc, HandlerFunc]] = []
            # тут будут другие поля, нужные для работы класса бота
            # ты ведь знаешь, как работают классы в питоне?
            self._recognizer = sr.Recognizer()
        
        def say(self, text: str) -> None:
            """Обработчики могут вызвать say(), чтобы бот что-нибудь сказал или написал."""
            print(text)  # пока что бот просто пишет ответ в консоль
        
        def register(self, condition: t.Union[str, t.List[str], PredicateFunc]):  # принимает строку, список строк или готовую функцию-предикат
            """Этот метод используется как декоратор для регистрации обработчика.
            Он может принимать как готовую функцию-предикат, так и просто строку/строки, с которых должна начинаться команда.
            В этом случае он подготовит нужный предикат самостоятельно.
            """
            if isinstance(condition, str):  # получили строку? переделаем её в предикат
                s_lower = s.lower()
                
                def predicate(text: str) -> bool:  # объявления функций могут быть вложенными
                    return text.lower().startswith(s_lower)  # если команда начинается с этой строки
                
            elif isinstance(condition, (list, tuple)):  # получили список строк
                strings_lower = [s.lower() for s in condition]  # делаем список строк в нижнем регистре
                
                def predicate(text: str) -> bool:  # объявления функций могут быть вложенными
                    return any(text.lower().startswith(s) for s in strings_lower)  # если любая из строк подошла
                
            else:  # получили готовую функцию-предикат - используем её как есть
                predicate = condition
            
            def decorator(handler: HandlerFunc):  # фактический декоратор получит на вход функцию-обработчик
                self._handlers.append((predicate, handler))  # запоминаем пару предикта-обработчик
                return handler  # декоратор должен вернуть функцию
            
            return decorator
        
        def _find_correct_handler(self, command: str) -> t.Union[HandlerFunc, None]:
            """Этот метод определяет, какой из известных обработчиков подойдёт к команде command."""
            for predicate, handler in self._handlers:
                try:
                    if predicate(command):  # предикат сказал "да"
                        return handler  # значит, этот обработчик и будем использовать
                except Exception as err:  # что-то пошло не так с предикатом
                    print(f'Predicate error for handler {handler!r}', err)  # сообщаем об ошибке, ищем дальше
            # если дошли досюда, мы не нашли подходящий обработчик
            return None  # вернём None как признак неудачи
        
        def do_one_command(self):
            """Этот метод запишет и обработает одну команду."""
            try:
                with sr.Microphone(device_index = 1) as source:
                    print('Настраиваюсь.')
                    self._recognizer.adjust_for_ambient_noise(source, duration=0.6)
                    print('Слушаю...')
                    audio = self._recognizer.listen(source)
                print('Услышал.')
                query = self._recognizer.recognize_google(audio, language = 'ru-RU')
            except Exception as err:  # никогда не "глотай" ошибки - хотя бы выведи их в журнал ,если не знаешь, что с ними делать.
                self.say('Ошибка при записи/распознавании!')  # даём знать пользователю
                print(err)  # это сообщение об ошибке нужно будет проанализировать, чтобы понять где ошибка
                return
            text = query.lower()
            print(f'Вы сказали: {text}')
            if not text.startswith(self._name):  # текст начинается не с нашего ключевого слова (имени) - игнорируем
                return
            text = text[len(self._name):].strip()  # убираем имя из текста
            handler = self._find_correct_handler(text)  # ищем обработчик
            if handler is None:  # не нашли
                self.say("Я не понимаю, что вы хотите.")  # так и говорим пользователю
                return
            # если дошли досюда - значит нашли
            try:
                handler(self, text)  # вызываем обработчик команды
            except Exception as err:  # он может потерпеть неудачу
                self.say("Произошла ошибка")  # так и говорим пользователю
                print(err)  # это сообщение об ошибке нужно будет проанализировать, чтобы понять где ошибка



    А вот пример использования:
    if __name__ == '__main__':
        import webbrowser 
        
        bot = VoiceBot('ботва')  # "Ботва" - ключевое слово (имя) бота.
        
        # описываем и регистрируем обработчик команды
        @bot.register(['открой контакт', 'открой вк'])  # должен сработать на "ботва открой контакт", например
        def command_vk(bot, text):
            webbrowser.open('https://vk.com', new=1)
            bot.say('Готово.')
        
        # рабочий цикл бота
        while True:
            bot.do_one_command()

    Как видишь, это очень похоже на код, который получается при использовании готовых библиотек для создания чат-ботов (текстовых). Потому что идеи, лежащие в основе, одни и те же.

    Как работают декораторы?

    Если коротко, то вот этот код:
    @bot.register(['открой контакт', 'открой вк'])
    def command_vk(bot, text):
        webbrowser.open('https://vk.com', new=1)
        bot.say('Готово.')

    эквивалентен вот такому коду:
    _decorator_func = bot.register(['открой контакт', 'открой вк'])  # готовим функцию-декоратор
    
    def command_vk(bot, text):  # описываем декорируемую функцию
        webbrowser.open('https://vk.com', new=1)
        bot.say('Готово.')
    
    _decorated_func = _decorator_func(command_vk)  # вызываем декоратор на этой функции
    command_vk = _decorated_func  # заменяем декорируемую функцию на то, что вернул декоратор



    Да, боты - это ни разу не просто.
    Ответ написан
    Комментировать
  • Как вывести списки в 2 столбца?

    Vindicar
    @Vindicar
    RTFM!
    По-моему, второй for должен быть на одном уровне с первым, а не вложен в первый.
    Проверь отступы.
    Ответ написан
    1 комментарий
  • Почему типы полей структуры в качестве указателя не соответствуют своим размерам в памяти (target wasm32)?

    Vindicar
    @Vindicar
    RTFM!
    Выравнивание по 32 бита.
    Некоторые архитектуры процов вообще требуют, чтобы целое размером N байт имело адрес кратный N.

    Для других это не обязательно, но доступ по адресам, кратным разрядности, быстрее. Так что компиляторы часто вставляют неиспользуемые байты в структуру, чтобы подвинуть следующее поле на "удобный" адрес. В плюсах (а может и в си) вроде есть директива #pragma pack, которая эти м управляет. Насчёт раста не знаю.
    Ответ написан
    3 комментария
  • Как сделать относительный импорт без родительского пакета?

    Vindicar
    @Vindicar
    RTFM!
    Никак. Пакеты могут импортировать другие пакеты на одном с ними уровне или уровнем ниже, но не могут импортировать файлы из пакетов уровнем выше.

    Если, конечно, не манипулировать механизмом импорта. Он это позволяет, но обычно овчинка выделки не стоит.
    Так что проще закинуть module1 в каталог(пакет) и импортировать его как package1.module1.

    А вообще очень странное решение - почему скрипт верхнего уровня в каталоге, а импортируемые модули - нет?
    Ответ написан
    Комментировать
  • Почему не работает метод send_keys?

    Vindicar
    @Vindicar
    RTFM!
    <input type="search" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_3_list" aria-autocomplete="list" aria-controls="rc_select_3_list" aria-activedescendant="rc_select_3_list_0" value="" id="rc_select_3" style="opacity: 0;" aria-expanded="false" readonly="" unselectable="on">


    readonly="" unselectable="on"

    Может, поэтому?
    Ответ написан
    1 комментарий
  • Как заставить def работать?

    Vindicar
    @Vindicar
    RTFM!
    Поучи язык. Просто поучи, без ботов.
    def объявляет функцию, но не вызывает её.
    Ты её объявляешь внутри record_volume(), но ничего с ней не делаешь.
    Ответ написан
    Комментировать
  • Как задать несколько значений одной команде?

    Vindicar
    @Vindicar
    RTFM!
    cоздать несколько отдельных BACK, но не меняя самого текстового значения?


    Освой finite state machines (FSM).
    Ответ написан
    2 комментария
  • Как добавить таймер?

    Vindicar
    @Vindicar
    RTFM!
    Elacov_top, для извлечения фрагментов из текста можно использовать регулярные выражения. Это позволит разбирать только фиксированный набор фраз, но этого зачастую хватает. Хуже с тем. что слово "пять" надо будет превратить в 5. Тут я даже навскидку не подскажу. Хотя есть средства разбора естественных языков, типа такого.

    У тебя другая проблема, поважнее. Ты представляешь, как вырастет твой if-if-if спустя 5-10 фич?
    Нужно декомпозировать простыню кода на отдельные части.
    Ответ написан
  • Почему после нажатия inline кнопки бот не запускает ее обработчик?

    Vindicar
    @Vindicar
    RTFM!
    lambda call: 'season'
    Это работает не так. Читай документацию.
    Лямбда должна вернуть истинное булево значение, если обработчик может обработать этот запрос, и ложное - если нет.
    Внезапно, любая непустая строка интерпретируется как истина. А значит, первый обработчик получает все запросы.
    Сравнивай call.data с искомой строкой.
    Ответ написан
    3 комментария
  • Почему дублируются байты, которые не влезли в размер буффера, при получении с помощью socket.recv?

    Vindicar
    @Vindicar
    RTFM!
    try:
                                data = self.sock.recv(constants.BUF_SIZE)
                            except socket.timeout:
                                message_ended = True
    
                            buff += data

    Если отработает except, предыдущее значение data не изменится, и к buff оно ВСЁ РАВНО приклеится.
    Закинь buff += data в ветку try-else.
    Ответ написан
    Комментировать
  • Как запустить код без ошибок?

    Vindicar
    @Vindicar
    RTFM!
    В коде отсутствует запуск бота. Так что он делает именно то, что от него просят.
    Ответ написан
    Комментировать
  • Json ключ value не парсится?

    Vindicar
    @Vindicar
    RTFM!
    Ну наверно нужно не цикл вкладывать в try, а наоборот?
    Ответ написан
  • Почему в БД значение меняется на 0?

    Vindicar
    @Vindicar
    RTFM!
    except:
                    db.set_active(row[0], 0)


    Ну а нечего делать голый except. У тебя при абсолютно любой ошибке отправки пользователь молча помечается как неактивный, даже если это какой-то несвязанный твой косяк. Выясни, какое именно исключение кидается при заблокированном получателе, и лови только его. Остальные исключения журналируй.
    Ответ написан
  • Можно ли прервать input()?

    Vindicar
    @Vindicar
    RTFM!
    Нет, стандартный input() этого не предусматривает.
    Но есть сторонние варианты, например, pytimedinput.
    Ответ написан
    Комментировать
  • Как реализовать остановку цикла for?

    Vindicar
    @Vindicar
    RTFM!
    Если тебе нужна проверка на останов после каждой операции - придётся-таки эту проверку производить после каждой операции. Да, можно схитрить, но от этого не уйдёшь.

    Я могу посоветовать убрать time.sleep() и заменить их на threading.Event.wait() с таймаутом - в этом случае, если Event будет взведено, то не придётся "досыпать". Но проверять исход ожидания всё равно придётся самому.

    Альтернативное, но ОЧЕНЬ кардинальное решение - сделать код асинхронным. Причина в том, что у асинхронных подпрограмм, завёрнутых в Task, есть механизм отмены, позволяющий принудительно выкинуть исключение в ходе выполнения любой длительной операции (любого await-вызова). По сути, это та же самая проверка - но встроенная.

    Это работает, так как асинхронный код выполняется в одном потоке. Провернуть такой же фокус, скажем, в многопоточном приложении - нетривиально и довольно рискованно.
    Ответ написан
    2 комментария
  • Почему не работает IF-ELSE?

    Vindicar
    @Vindicar
    RTFM!
    1. Как проверял? Просто пытался угадать? Рандом - штука такая, могло просто не везти.
    2. Если пользователь с первого раза введёт правильный key, условие цикла сразу будет False, и цикл не выполнится - а значит, не выполнятся и ifы.

    Я бы посоветовал сделать так:
    max_tries = 5  # число попыток
    key = -1  # заведомо некорректное значение
    for i in range(1, max_tries+1):
        key = int(input(f'Попытка №{i}: '))
        if key == lock:
            print(f'Угадал c {i}-й попытки!')
            break
    else:  # этот else относится к for! 
        # он выполнится, если for НЕ БЫЛ прерван по break
        print('Попытки кончились. =(')
    Ответ написан
    1 комментарий
  • Как инициализировать декоратор в классе, а внутри использовать этот декоратор?

    Vindicar
    @Vindicar
    RTFM!
    Ты хочешь поместить хэндлеры в класс?
    Я в таких случаях делаю немного иначе.
    Делаю свой декоратор, который принимает те же параметры, что и ботовый, но просто сохраняет их в отдельном атрибуте декорируемого метода. Благо методу можно создать новый атрибут через setattr() или простым присваиванием.
    При конструировании экземпляра класса через dir() перечисляю содержимое класса, ищу методы, среди них ищу методы с моим атрибутом (т.е. те, которые были декорированы). Для каждого такого метода получаю bound method (через getattr(self, method_name)) и вызываю оригинальный декоратор на нём с сохранёнными параметрами. Ведь декоратор - это функция, его можно вызывать как функцию.
    Часть, связанную с конструированием, можно спрятать или в родительском абстрактном классе, или в метаклассе, чтобы не повторять для каждого класса с обработчиками.
    Ответ написан
    Комментировать
  • Как можно сделать виртуальную «флешку», которая будет отображаться в проводнике windows 10?

    Vindicar
    @Vindicar
    RTFM!
    Вариант А. Написать и установить драйвер виртуальной файловой системы. Разумеется, не на питоне.

    Вариант Б. Создать сетевой ресурс (можно на localhost, т.е. "как бы" сетевой), поддерживающий протокол WebDAV или иной, поддерживаемый виндой (как делает та же Samba) и примонтировать его через системную команду net use.
    Это если нужен именно виртуальный диск.

    Вариант В. Есть ещё Windows Shell Namespace Extension для создания виртуальных папок. Вроде как не рекомендуется.

    Вариант Г. Cloud Sync Engine.

    Я бы сказал, вариант Б наиболее реализуем именно на питоне. Плюс он более кроссплатформенный, и в принципе можно разместить скрипт не на локальной машине, а в сети.
    Ответ написан
    Комментировать