Как написать голосового помощника на python

Время на прочтение
16 мин

Количество просмотров 105K

Введение

Технологии в области машинного обучения за последний год развиваются с потрясающей скоростью. Всё больше компаний делятся своими наработками, тем самым открывая новые возможности для создания умных цифровых помощников.

В рамках данной статьи я хочу поделиться своим опытом реализации голосового ассистента и предложить вам несколько идей для того, чтобы сделать его ещё умнее и полезнее.

image

Что умеет мой голосовой ассистент?

Шаг 1. Обработка голосового ввода

Начнём с того, что научимся обрабатывать голосовой ввод. Нам потребуется микрофон и пара установленных библиотек: PyAudio и SpeechRecognition.

Подготовим основные инструменты для распознавания речи:

import speech_recognition

if __name__ == "__main__":

    # инициализация инструментов распознавания и ввода речи
    recognizer = speech_recognition.Recognizer()
    microphone = speech_recognition.Microphone()

    while True:
        # старт записи речи с последующим выводом распознанной речи 
        voice_input = record_and_recognize_audio()
        print(voice_input)

Теперь создадим функцию для записи и распознавания речи. Для онлайн-распознавания нам потребуется Google, поскольку он имеет высокое качество распознавания на большом количестве языков.

def record_and_recognize_audio(*args: tuple):
    """
    Запись и распознавание аудио
    """
    with microphone:
        recognized_data = ""

        # регулирование уровня окружающего шума
        recognizer.adjust_for_ambient_noise(microphone, duration=2)

        try:
            print("Listening...")
            audio = recognizer.listen(microphone, 5, 5)

        except speech_recognition.WaitTimeoutError:
            print("Can you check if your microphone is on, please?")
            return

        # использование online-распознавания через Google 
        try:
            print("Started recognition...")
            recognized_data = recognizer.recognize_google(audio, language="ru").lower()

        except speech_recognition.UnknownValueError:
            pass

        # в случае проблем с доступом в Интернет происходит выброс ошибки
        except speech_recognition.RequestError:
            print("Check your Internet Connection, please")

        return recognized_data

А что делать, если нет доступа в Интернет? Можно воспользоваться решениями для offline-распознавания. Мне лично безумно понравился проект Vosk.

На самом деле, необязательно внедрять offline-вариант, если он вам не нужен. Мне просто хотелось показать оба способа в рамках статьи, а вы уже выбирайте, исходя из своих требований к системе (например, по количеству доступных языков распознавания бесспорно лидирует Google).

Теперь, внедрив offline-решение и добавив в проект нужные языковые модели, при отсутствии доступа к сети у нас автоматически будет выполняться переключение на offline-распознавание.

Замечу, что для того, чтобы не нужно было два раза повторять одну и ту же фразу, я решила записывать аудио с микрофона во временный wav-файл, который будет удаляться после каждого распознавания.

Таким образом, полученный код выглядит следующим образом:

Полный код для работы распознавания речи

from vosk import Model, KaldiRecognizer  # оффлайн-распознавание от Vosk
import speech_recognition  # распознавание пользовательской речи (Speech-To-Text)
import wave  # создание и чтение аудиофайлов формата wav
import json  # работа с json-файлами и json-строками
import os  # работа с файловой системой


def record_and_recognize_audio(*args: tuple):
    """
    Запись и распознавание аудио
    """
    with microphone:
        recognized_data = ""

        # регулирование уровня окружающего шума
        recognizer.adjust_for_ambient_noise(microphone, duration=2)

        try:
            print("Listening...")
            audio = recognizer.listen(microphone, 5, 5)

            with open("microphone-results.wav", "wb") as file:
                file.write(audio.get_wav_data())

        except speech_recognition.WaitTimeoutError:
            print("Can you check if your microphone is on, please?")
            return

        # использование online-распознавания через Google 
        try:
            print("Started recognition...")
            recognized_data = recognizer.recognize_google(audio, language="ru").lower()

        except speech_recognition.UnknownValueError:
            pass

        # в случае проблем с доступом в Интернет происходит попытка 
        # использовать offline-распознавание через Vosk
        except speech_recognition.RequestError:
            print("Trying to use offline recognition...")
            recognized_data = use_offline_recognition()

        return recognized_data


def use_offline_recognition():
    """
    Переключение на оффлайн-распознавание речи
    :return: распознанная фраза
    """
    recognized_data = ""
    try:
        # проверка наличия модели на нужном языке в каталоге приложения
        if not os.path.exists("models/vosk-model-small-ru-0.4"):
            print("Please download the model from:n"
                  "https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
            exit(1)

        # анализ записанного в микрофон аудио (чтобы избежать повторов фразы)
        wave_audio_file = wave.open("microphone-results.wav", "rb")
        model = Model("models/vosk-model-small-ru-0.4")
        offline_recognizer = KaldiRecognizer(model, wave_audio_file.getframerate())

        data = wave_audio_file.readframes(wave_audio_file.getnframes())
        if len(data) > 0:
            if offline_recognizer.AcceptWaveform(data):
                recognized_data = offline_recognizer.Result()

                # получение данных распознанного текста из JSON-строки
                # (чтобы можно было выдать по ней ответ)
                recognized_data = json.loads(recognized_data)
                recognized_data = recognized_data["text"]
    except:
        print("Sorry, speech service is unavailable. Try again later")

    return recognized_data


if __name__ == "__main__":

    # инициализация инструментов распознавания и ввода речи
    recognizer = speech_recognition.Recognizer()
    microphone = speech_recognition.Microphone()

    while True:
        # старт записи речи с последующим выводом распознанной речи
        # и удалением записанного в микрофон аудио
        voice_input = record_and_recognize_audio()
        os.remove("microphone-results.wav")
        print(voice_input)

Возможно, вы спросите «А зачем поддерживать offline-возможности?»

Я считаю, что всегда стоит учитывать, что пользователь может быть отрезан от сети. В таком случае, голосовой ассистент всё еще может быть полезным, если использовать его как разговорного бота или для решения ряда простых задач, например, посчитать что-то, порекомендовать фильм, помочь сделать выбор кухни, сыграть в игру и т.д.

Шаг 2. Конфигурация голосового ассистента

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

Для того, чтобы задать нашему ассистенту голос, мы воспользуемся библиотекой для offline-синтеза речи pyttsx3. Она автоматически найдет голоса, доступные для синтеза на нашем компьютере в зависимости от настроек операционной системы (поэтому, возможно, что у вас могут быть доступны другие голоса и вам нужны будут другие индексы).

Также добавим в в main-функцию инициализацию синтеза речи и отдельную функцию для её проигрывания. Чтобы убедиться, что всё работает, сделаем небольшую проверку на то, что пользователь с нами поздоровался, и выдадим ему обратное приветствие от ассистента:

Полный код основы голосового ассистента (синтез и распознавание речи)

from vosk import Model, KaldiRecognizer  # оффлайн-распознавание от Vosk
import speech_recognition  # распознавание пользовательской речи (Speech-To-Text)
import pyttsx3  # синтез речи (Text-To-Speech)
import wave  # создание и чтение аудиофайлов формата wav
import json  # работа с json-файлами и json-строками
import os  # работа с файловой системой


class VoiceAssistant:
    """
    Настройки голосового ассистента, включающие имя, пол, язык речи
    """
    name = ""
    sex = ""
    speech_language = ""
    recognition_language = ""


def setup_assistant_voice():
    """
    Установка голоса по умолчанию (индекс может меняться в 
    зависимости от настроек операционной системы)
    """
    voices = ttsEngine.getProperty("voices")

    if assistant.speech_language == "en":
        assistant.recognition_language = "en-US"
        if assistant.sex == "female":
            # Microsoft Zira Desktop - English (United States)
            ttsEngine.setProperty("voice", voices[1].id)
        else:
            # Microsoft David Desktop - English (United States)
            ttsEngine.setProperty("voice", voices[2].id)
    else:
        assistant.recognition_language = "ru-RU"
        # Microsoft Irina Desktop - Russian
        ttsEngine.setProperty("voice", voices[0].id)


def play_voice_assistant_speech(text_to_speech):
    """
    Проигрывание речи ответов голосового ассистента (без сохранения аудио)
    :param text_to_speech: текст, который нужно преобразовать в речь
    """
    ttsEngine.say(str(text_to_speech))
    ttsEngine.runAndWait()


def record_and_recognize_audio(*args: tuple):
    """
    Запись и распознавание аудио
    """
    with microphone:
        recognized_data = ""

        # регулирование уровня окружающего шума
        recognizer.adjust_for_ambient_noise(microphone, duration=2)

        try:
            print("Listening...")
            audio = recognizer.listen(microphone, 5, 5)

            with open("microphone-results.wav", "wb") as file:
                file.write(audio.get_wav_data())

        except speech_recognition.WaitTimeoutError:
            print("Can you check if your microphone is on, please?")
            return

        # использование online-распознавания через Google 
        # (высокое качество распознавания)
        try:
            print("Started recognition...")
            recognized_data = recognizer.recognize_google(audio, language="ru").lower()

        except speech_recognition.UnknownValueError:
            pass

        # в случае проблем с доступом в Интернет происходит 
        # попытка использовать offline-распознавание через Vosk
        except speech_recognition.RequestError:
            print("Trying to use offline recognition...")
            recognized_data = use_offline_recognition()

        return recognized_data


def use_offline_recognition():
    """
    Переключение на оффлайн-распознавание речи
    :return: распознанная фраза
    """
    recognized_data = ""
    try:
        # проверка наличия модели на нужном языке в каталоге приложения
        if not os.path.exists("models/vosk-model-small-ru-0.4"):
            print("Please download the model from:n"
                  "https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
            exit(1)

        # анализ записанного в микрофон аудио (чтобы избежать повторов фразы)
        wave_audio_file = wave.open("microphone-results.wav", "rb")
        model = Model("models/vosk-model-small-ru-0.4")
        offline_recognizer = KaldiRecognizer(model, wave_audio_file.getframerate())

        data = wave_audio_file.readframes(wave_audio_file.getnframes())
        if len(data) > 0:
            if offline_recognizer.AcceptWaveform(data):
                recognized_data = offline_recognizer.Result()

                # получение данных распознанного текста из JSON-строки 
                # (чтобы можно было выдать по ней ответ)
                recognized_data = json.loads(recognized_data)
                recognized_data = recognized_data["text"]
    except:
        print("Sorry, speech service is unavailable. Try again later")

    return recognized_data


if __name__ == "__main__":

    # инициализация инструментов распознавания и ввода речи
    recognizer = speech_recognition.Recognizer()
    microphone = speech_recognition.Microphone()

    # инициализация инструмента синтеза речи
    ttsEngine = pyttsx3.init()

    # настройка данных голосового помощника
    assistant = VoiceAssistant()
    assistant.name = "Alice"
    assistant.sex = "female"
    assistant.speech_language = "ru"

    # установка голоса по умолчанию
    setup_assistant_voice()

    while True:
        # старт записи речи с последующим выводом распознанной речи
        # и удалением записанного в микрофон аудио
        voice_input = record_and_recognize_audio()
        os.remove("microphone-results.wav")
        print(voice_input)

        # отделение комманд от дополнительной информации (аргументов)
        voice_input = voice_input.split(" ")
        command = voice_input[0]

        if command == "привет":
            play_voice_assistant_speech("Здравствуй")

На самом деле, здесь бы хотелось самостоятельно научиться писать синтезатор речи, однако моих знаний здесь не будет достаточно. Если вы можете подсказать хорошую литературу, курс или интересное документированное решение, которое поможет разобраться в этой теме глубоко — пожалуйста, напишите в комментариях.

Шаг 3. Обработка команд

Теперь, когда мы «научились» распознавать и синтезировать речь с помощью просто божественных разработок наших коллег, можно начать изобретать свой велосипед для обработки речевых команд пользователя :D

В моём случае я использую мультиязычные варианты хранения команд, поскольку у меня в демонстрационном проекте не так много событий, и меня устраивает точность определения той или иной команды. Однако, для больших проектов я рекомендую разделить конфигурации по языкам.

Для хранения команд я могу предложить два способа.

1 способ

Можно использовать прекрасный JSON-подобный объект, в котором хранить намерения, сценарии развития, ответы при неудавшихся попытках (такие часто используются для чат-ботов). Выглядит это примерно вот так:

config = {
    "intents": {
        "greeting": {
            "examples": ["привет", "здравствуй", "добрый день",
                         "hello", "good morning"],
            "responses": play_greetings
        },
        "farewell": {
            "examples": ["пока", "до свидания", "увидимся", "до встречи",
                         "goodbye", "bye", "see you soon"],
            "responses": play_farewell_and_quit
        },
        "google_search": {
            "examples": ["найди в гугл",
                         "search on google", "google", "find on google"],
            "responses": search_for_term_on_google
        },
    },
    "failure_phrases": play_failure_phrase
}

Такой вариант подойдёт тем, кто хочет натренировать ассистента на то, чтобы он отвечал на сложные фразы. Более того, здесь можно применить NLU-подход и создать возможность предугадывать намерение пользователя, сверяя их с теми, что уже есть в конфигурации.

Подробно этот способ мы его рассмотрим на 5 шаге данной статьи. А пока обращу ваше внимание на более простой вариант

2 способ

Можно взять упрощенный словарь, у которого в качестве ключей будет hashable-тип tuple (поскольку словари используют хэши для быстрого хранения и извлечения элементов), а в виде значений будут названия функций, которые будут выполняться. Для коротких команд подойдёт вот такой вариант:

commands = {
    ("hello", "hi", "morning", "привет"): play_greetings,
    ("bye", "goodbye", "quit", "exit", "stop", "пока"): play_farewell_and_quit,
    ("search", "google", "find", "найди"): search_for_term_on_google,
    ("video", "youtube", "watch", "видео"): search_for_video_on_youtube,
    ("wikipedia", "definition", "about", "определение", "википедия"): search_for_definition_on_wikipedia,
    ("translate", "interpretation", "translation", "перевод", "перевести", "переведи"): get_translation,
    ("language", "язык"): change_language,
    ("weather", "forecast", "погода", "прогноз"): get_weather_forecast,
}

Для его обработки нам потребуется дополнить код следующим образом:

def execute_command_with_name(command_name: str, *args: list):
    """
    Выполнение заданной пользователем команды с дополнительными аргументами
    :param command_name: название команды
    :param args: аргументы, которые будут переданы в функцию
    :return:
    """
    for key in commands.keys():
        if command_name in key:
            commands[key](*args)
        else:
            pass  # print("Command not found")


if __name__ == "__main__":

    # инициализация инструментов распознавания и ввода речи
    recognizer = speech_recognition.Recognizer()
    microphone = speech_recognition.Microphone()

    while True:
        # старт записи речи с последующим выводом распознанной речи
        # и удалением записанного в микрофон аудио
        voice_input = record_and_recognize_audio()
        os.remove("microphone-results.wav")
        print(voice_input)

        # отделение комманд от дополнительной информации (аргументов)
        voice_input = voice_input.split(" ")
        command = voice_input[0]
        command_options = [str(input_part) for input_part in voice_input[1:len(voice_input)]]
        execute_command_with_name(command, command_options)

В функции будут передаваться дополнительные аргументы, сказанные после командного слова. То есть, если сказать фразу «видео милые котики«, команда «видео» вызовет функцию search_for_video_on_youtube() с аргументом «милые котики» и выдаст вот такой результат:

image

Пример такой функции с обработкой входящих аргументов:

def search_for_video_on_youtube(*args: tuple):
    """
    Поиск видео на YouTube с автоматическим открытием ссылки на список результатов
    :param args: фраза поискового запроса
    """
    if not args[0]: return
    search_term = " ".join(args[0])
    url = "https://www.youtube.com/results?search_query=" + search_term
    webbrowser.get().open(url)

    # для мультиязычных голосовых ассистентов лучше создать 
    # отдельный класс, который будет брать перевод из JSON-файла
    play_voice_assistant_speech("Here is what I found for " + search_term + "on youtube")

Ну вот и всё! Основной функционал бота готов. Далее вы можете до бесконечности улучшать его различными способами. Моя реализация с подробными комментариями доступна на моём GitHub.

Ниже мы рассмотрим ряд улучшений, чтобы сделать нашего ассистента ещё умнее.

Шаг 4. Добавление мультиязычности

Чтобы научить нашего ассистента работать с несколькими языковыми моделями, будет удобнее всего организовать небольшой JSON-файл с простой структурой:

{
  "Can you check if your microphone is on, please?": {
    "ru": "Пожалуйста, проверь, что микрофон включен",
    "en": "Can you check if your microphone is on, please?"
  },
  "What did you say again?": {
    "ru": "Пожалуйста, повтори",
    "en": "What did you say again?"
  },
}

В моём случае я использую переключение между русским и английским языком, поскольку мне для этого доступны модели для распознавания речи и голоса для синтеза речи. Язык будет выбран в зависимости от языка речи самого голосового ассистента.

Для того, чтобы получать перевод мы можем создать отдельный класс с методом, который будет возвращать нам строку с переводом:

class Translation:
    """
    Получение вшитого в приложение перевода строк для 
    создания мультиязычного ассистента
    """
    with open("translations.json", "r", encoding="UTF-8") as file:
        translations = json.load(file)


    def get(self, text: str):
        """
        Получение перевода строки из файла на нужный язык (по его коду)
        :param text: текст, который требуется перевести
        :return: вшитый в приложение перевод текста
        """
        if text in self.translations:
            return self.translations[text][assistant.speech_language]
        else:
            # в случае отсутствия перевода происходит вывод сообщения 
            # об этом в логах и возврат исходного текста
            print(colored("Not translated phrase: {}".format(text), "red"))
            return text

В main-функции до цикла объявим наш переводчик таким образом: translator = Translation()

Теперь при проигрывании речи ассистента мы сможем получить перевод следующим образом:

play_voice_assistant_speech(translator.get(
    "Here is what I found for {} on Wikipedia").format(search_term))

Как видно из примера выше, это работает даже для тех строк, которые требуют вставки дополнительных аргументов. Таким образом можно переводить «стандартные» наборы фраз для ваших ассистентов.

Шаг 5. Немного машинного обучения

А теперь вернёмся к характерному для большинства чат-ботов варианту с JSON-объектом для хранения команд из нескольких слов, о котором я упоминала в пункте 3. Он подойдёт для тех, кто не хочет использовать строгие команды и планирует расширить понимание намерений пользователя, используя NLU-методы.

Грубо говоря, в таком случае фразы «добрый день«, «добрый вечер» и «доброе утро» будут считаться равнозначными. Ассистент будет понимать, что во всех трёх случаях намерением пользователя было поприветствовать своего голосового помощника.

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

Для реализации такой возможности нам нужно будет добавить пару функций:

def prepare_corpus():
    """
    Подготовка модели для угадывания намерения пользователя
    """
    corpus = []
    target_vector = []
    for intent_name, intent_data in config["intents"].items():
        for example in intent_data["examples"]:
            corpus.append(example)
            target_vector.append(intent_name)

    training_vector = vectorizer.fit_transform(corpus)
    classifier_probability.fit(training_vector, target_vector)
    classifier.fit(training_vector, target_vector)


def get_intent(request):
    """
    Получение наиболее вероятного намерения в зависимости от запроса пользователя
    :param request: запрос пользователя
    :return: наиболее вероятное намерение
    """
    best_intent = classifier.predict(vectorizer.transform([request]))[0]

    index_of_best_intent = list(classifier_probability.classes_).index(best_intent)
    probabilities = classifier_probability.predict_proba(vectorizer.transform([request]))[0]

    best_intent_probability = probabilities[index_of_best_intent]

    # при добавлении новых намерений стоит уменьшать этот показатель
    if best_intent_probability > 0.57:
        return best_intent

А также немного модифицировать main-функцию, добавив инициализацию переменных для подготовки модели и изменив цикл на версию, соответствующую новой конфигурации:

# подготовка корпуса для распознавания запросов пользователя с некоторой вероятностью
# (поиск похожих)
vectorizer = TfidfVectorizer(analyzer="char", ngram_range=(2, 3))
classifier_probability = LogisticRegression()
classifier = LinearSVC()
prepare_corpus()

while True:
    # старт записи речи с последующим выводом распознанной речи 
    # и удалением записанного в микрофон аудио
    voice_input = record_and_recognize_audio()

    if os.path.exists("microphone-results.wav"):
        os.remove("microphone-results.wav")

    print(colored(voice_input, "blue"))

    # отделение команд от дополнительной информации (аргументов)
    if voice_input:
        voice_input_parts = voice_input.split(" ")

        # если было сказано одно слово - выполняем команду сразу 
        # без дополнительных аргументов
        if len(voice_input_parts) == 1:
            intent = get_intent(voice_input)
            if intent:
                config["intents"][intent]["responses"]()
            else:
                config["failure_phrases"]()

        # в случае длинной фразы - выполняется поиск ключевой фразы 
        # и аргументов через каждое слово,
        # пока не будет найдено совпадение
        if len(voice_input_parts) > 1:
            for guess in range(len(voice_input_parts)):
                intent = get_intent((" ".join(voice_input_parts[0:guess])).strip())
                if intent:
                    command_options = [voice_input_parts[guess:len(voice_input_parts)]]
                    config["intents"][intent]["responses"](*command_options)
                    break
                if not intent and guess == len(voice_input_parts)-1:
                    config["failure_phrases"]()

Однако, такой способ сложнее контролировать: он требует постоянной проверки того, что та или иная фраза всё ещё верно определяется системой как часть того или иного намерения. Поэтому данным способом стоит пользоваться с аккуратностью (либо экспериментировать с самой моделью).

Заключение

На этом мой небольшой туториал подошёл к концу.

Мне будет приятно, если вы поделитесь со мной в комментариях известными вам open-source решениями, которые можно внедрить в данный проект, а также вашими идеями касательно того, какие ещё online и offline-функции можно реализовать.

Документированные исходники моего голосового ассистента в двух вариантах можно найти здесь.

P.S: решение работает на Windows, Linux и MacOS с незначительными различиями при установке библиотек PyAudio и Google.

Кстати, тех, кто планирует строить карьеру в IT, я буду рада видеть на своём YouTube-канале IT DIVA. Там вы сможете найти видео по тому, как оформлять GitHub, проходить собеседования, получать повышение, справляться с профессиональным выгоранием, управлять разработкой и т.д.

Я думаю что все знают голосового помощника Джарвиса из фильма «Железный человек». И много кто мечтал сделать голосового помощника своими руками. В этой статье мы его напишем.

Что понадобится

  • Python версии 3.6.8
  • Установленные по порядку модули: Librariespywin32, pipywin32, pyttsx3, SpeechRecognition, PyAudio, fuzzywuzzy, pyowm, python‑Levenshtein, CurrencyConverter.

Написание самого помощник

Создаём в папке вот такие файлы:

functions.py

Открываем файл functions.py и импортируем библиотеки и остальные файлы:

import pyttsx3
import speech_recognition as sr
import os
from fuzzywuzzy import fuzz
import datetime
import win32com.client as wincl
import site
import calculator
import envelope
import translator

После этого вставляем данный код и вписываем в строку alias название помощника(у нас pythonguru):

opts = {«alias»: (‘pythonguru’, ‘пайтонгуру’, ‘гурупайтон’),
«tbr»: (‘скажи’, ‘расскажи’, ‘покажи’, ‘сколько’, ‘произнеси’, ‘как’,’сколько’,’поставь’,’переведи’, «засеки»,’запусти’,’сколько будет’),
«cmds»:
{«ctime»: (‘текущее время’, ‘сейчас времени’, ‘который час’, ‘время’, ‘какое сейчас время’),
‘startStopwatch’: (‘запусти секундомер’, «включи секундомер», «засеки время»),
‘stopStopwatch’: (‘останови секундомер’, «выключи секундомер», «останови»),
«stupid1»: (‘расскажи анекдот’, ‘рассмеши меня’, ‘ты знаешь анекдоты’, «шутка», «прикол»),
«calc»: (‘прибавить’,’умножить’,’разделить’,’степень’,’вычесть’,’поделить’,’х’,’+’,’-‘,’/’),
«shutdown»: (‘выключи’, ‘выключить’, ‘отключение’, ‘отключи’, ‘выключи компьютер’),
«conv»: («валюта», «конвертер»,»доллар»,’руб’,’евро’),
«internet»: («открой», «вк», «гугл», «сайт», ‘вконтакте’, «ютуб»),
«translator»: («переводчик»,»translate»),
«deals»: («дела»,»делишки», ‘как сам’, ‘как дела’)}}

Дальше подключаем микрофон и голос самого помощника

startTime = 0
speak_engine = pyttsx3.init()
voices = speak_engine.getProperty(‘voices’)
speak_engine.setProperty(‘voice’, voices[2].id)
r = sr.Recognizer()
m = sr.Microphone(device_index=1)
voice = «str»

Если у вас не работает микрофон то пробуйте менять значение device_index=1 (например на device_index=2)

Далее вставляем весь этот код (функции разговора ассистента, фунции прослушки микрофона и возможности самого ассистента):

def speak(what):
print(what)
speak = wincl.Dispatch(«SAPI.SpVoice»)
speak.Speak(what)

def callback(recognizer, audio):
try:
global voice
voice = recognizer.recognize_google(audio, language=»ru-RU»).lower()

print(«[log] Распознано: » + voice)

if voice.startswith(opts[«alias»]):
cmd = voice

for x in opts[‘alias’]:
cmd = cmd.replace(x, «»).strip()

for x in opts[‘tbr’]:
cmd = cmd.replace(x, «»).strip()
voice = cmd
# распознаем и выполняем команду
cmd = recognize_cmd(cmd)
execute_cmd(cmd[‘cmd’])

except sr.UnknownValueError:
print(«[log] Голос не распознан!»)
except sr.RequestError as e:
print(«[log] Неизвестная ошибка, проверьте интернет!»)
def listen():
with m as source:
r.adjust_for_ambient_noise(source)
stop_listening = r.listen_in_background(m, callback)
while True: time.sleep(0.1)

def recognize_cmd(cmd):
RC = {‘cmd’: », ‘percent’: 0}
for c, v in opts[‘cmds’].items():
for x in v:
vrt = fuzz.ratio(cmd, x)
if vrt > RC[‘percent’]:
RC[‘cmd’] = c
RC[‘percent’] = vrt
return RC
ef execute_cmd(cmd):
global startTime
if cmd == ‘ctime’:
now = datetime.datetime.now()
speak(«Сейчас {0}:{1}».format(str(now.hour), str(now.minute)))
elif cmd == ‘shutdown’:
os.system(‘shutdown -s’)
speak(«Выключаю…»)
elif cmd == ‘calc’:
calc.calculator()
elif cmd == ‘conv’:
convert.convertation()
elif cmd == ‘translator’:
translate.translate()
elif cmd == ‘stupid1’:
anekdot.fun()
elif cmd == ‘internet’:
browser.browser()
elif cmd == ‘startStopwatch’:
speak(«Секундомер запущен»)
startTime = time.time()
elif cmd == «stopStopwatch»:
if startTime != 0:
Time = time.time() — startTime
speak(f»Прошло {round(Time // 3600)} часов {round(Time // 60)} минут {round(Time % 60, 2)} секунд»)
startTime = 0
else:
speak(«Секундомер не включен»)
elif cmd == ‘deals’:
speak(«Пока отлично.»)
else:
print(«Команда не распознана!»)

start.py

Этот файл будет служить для запуска всего ассистента

import functions
import time
import datetime

now = datetime.datetime.now()

if now.hour >= 6 and now.hour < 12:
funcs.speak(«Доброе утро!»)
elif now.hour >= 12 and now.hour < 18:
funcs.speak(«Добрый день!»)
elif now.hour >= 18 and now.hour < 23:
funcs.speak(«Добрый вечер!»)
else:
funcs.speak(«Доброй ночи!»)

funcs.listen()

site.py

С его помощью мы будем открывать любые сайты.

import webbrowser
import funcs
def browser():
sites = {«https://vk.com»:[«vk»,»вк»], ‘https://www.youtube.com/’:[‘youtube’, ‘ютуб’], ‘https://ru.wikipedia.org’: [«вики», «wiki»], ‘https://ru.aliexpress.com’:[‘али’, ‘ali’, ‘aliexpress’, ‘алиэспресс’], ‘http://google.com’:[‘гугл’,’google’], ‘https://www.amazon.com’:[‘амазон’, ‘amazon’], ‘https://www.apple.com/ru’:[‘apple’,’эпл’] ‘
https://telete.in/gurupython’:[‘пайтонгуру’, ‘pythonguru’]}
site = funcs.voice.split()[-1]
for k, v in sites.items():
for i in v:
if i not in site.lower():
open_tab = None
else:
open_tab = webbrowser.open_new_tab(k)
break

if open_tab is not None:
break

calculator.py

Самый простейший калькулятор на пайтоне

import funcs
def calculator():
try:
list_of_nums = funcs.voice.split()
num_1,num_2 = int((list_of_nums[-3]).strip()), int((list_of_nums[-1]).strip())
opers = [list_of_nums[0].strip(),list_of_nums[-2].strip()]
for i in opers:
if ‘дел’ in i or ‘множ’ in i or ‘лож’ in i or ‘приба’ in i or ‘выч’ in i or i == ‘x’ or i == ‘/’ or i ==’+’ or i == ‘-‘ or i == ‘*’:
oper = i
break
else:
oper = opers[1]
if oper == «+» or ‘слож’ in oper:
ans = num_1 + num_2
elif oper == «-» or ‘выче’ in oper:
ans = num_1 — num_2
elif oper == «х» or ‘множ’ in oper:
ans = num_1 * num_2
elif oper == «/» or ‘дел’ in oper:
if num_2 != 0:
ans = num_1 / num_2
else:
funcs.speak(«Делить на ноль невозможно»)
elif «степен» in oper:
ans = num_1 ** num_2
funcs.speak(«{0} {1} {2} = {3}».format(list_of_nums[-3], list_of_nums[-2], list_of_nums[-1], ans))
except:
funcs.speak(«Скажите, например: Сколько будет 5+5?»)

envelope.py

Конвертер денег

from currency_converter import CurrencyConverter
import funcs
def convertation():
class CurrencyError(Exception):
pass
c = CurrencyConverter()
money = None
from_currency = None
to_currency = None
list_of_conv = funcs.voice.split()
if len(list_of_conv) > 4:
list_of_conv = list_of_conv[1:]
else:
print()
while money is None:
try:
money = list_of_conv[0]
except ValueError:
funcs.speak(«Скажите, к примеру: 50 долларов в рубли»)
break
while from_currency is None:
try:
list_of_conv[0] = int(list_of_conv[0])
except ValueError:
funcs.speak(«Скажите, к примеру: 50 долларов в рубли»)
break
try:
if «руб» in list_of_conv[1]:
from_currency = «RUB»
elif «дол» in list_of_conv[1]:
from_currency = «USD»
elif «евр» in list_of_conv[1]:
from_currency = «EUR»
if from_currency not in c.currencies:
raise CurrencyError

except (CurrencyError, IndexError):
from_currency = None
funcs.speak(«Скажите, например: 50 долларов в рубли»)
break

while to_currency is None:
try:
list_of_conv[0] = int(list_of_conv[0])
except ValueError:
return None
try:
if «руб» in list_of_conv[3]:
to_currency = «RUB»
elif «дол» in list_of_conv[3]:
to_currency = «USD»
elif «евр» in list_of_conv[3]:
to_currency = «EUR»
if to_currency not in c.currencies:
raise CurrencyError

except (CurrencyError, IndexError):
to_currency = None
funcs.speak(«Скажите, например: 50 долларов в рубли»)
break
while True:
try:
funcs.speak(f»{money} {from_currency} в {to_currency} — »
f»{round(c.convert(money, from_currency, to_currency), 2)}»)
break
except ValueError:
funcs.speak(«Скажите, например: 50 долларов в рубли»)
break

translator.py

Простой переводчик

import requests
import funcs

def translate():
url = ‘https://translate.yandex.net/api/v1.5/tr.json/translate?’
key = ‘trnsl.1.1.20190227T075339Z.1b02a9ab6d4a47cc.f37d50831b51374ee600fd6aa0259419fd7ecd97’
text = funcs.voice.split()[1:]
lang = ‘en-ru’
r = requests.post(url, data={‘key’: key, ‘text’: text, ‘lang’: lang}).json()
try:
funcs.speak(r[«text»])
except:
funcs.speak(«Обратитесь к переводчику, начиная со слова ‘Переводчик'»)

Как видите сделать своего голосового помощника на Python не так уж сложно, главное иметь знания об основах языка и всё получится.

Совершенствуй знания по Python каждый день у нас на телеграм канале, PythonGuru.

Big Data, Искусственный интеллект, Python, Data Mining


Рекомендация: подборка платных и бесплатных курсов Python — https://katalog-kursov.ru/

image

Всем привет!

Кто не хочет роскошь иметь помощника, который всегда прислушивается к вашему звонку, предвидит все ваши потребности и при необходимости принимает меры? Эта роскошь теперь доступна благодаря голосовым помощникам на основе искусственного интеллекта.

Голосовые помощники поставляются в небольших упаковках и могут выполнять различные действия, услышав вашу команду. Они могут включать свет, отвечать на вопросы, играть музыку, размещать онлайн-заказы и делать все виды искусственного интеллекта.

Голосовых помощников не следует путать с виртуальными помощниками, которые являются людьми, которые работают удаленно и поэтому могут выполнять все виды задач. Голосовые помощники основаны на технологии. По мере того, как голосовые помощники становятся более надежными, их полезность как в личной, так и в деловой сферах будет расти.

image

Что такое голосовой помощник?

Голосовой помощник или интеллектуальный личный помощник — это программный агент, который может выполнять задачи или услуги для человека на основе словесных команд, то есть путем интерпретации человеческой речи и ответа посредством синтезированных голосов. Пользователи могут задавать вопросы своему помощнику, с помощью устных команд, управлять устройствами домашней автоматизации и воспроизведением мультимедиа с помощью голоса, а также управлять другими основными задачами, такими как электронная почта, списки дел, открывать или закрывать любое приложение и т.д.

Позвольте мне привести вам пример Braina (Brain Artificial), которая является интеллектуальным личным помощником, интерфейсом на человеческом языке, программным обеспечением для автоматизации и распознавания голоса для ПК с Windows. Braina — это многофункциональное программное обеспечение для искусственного интеллекта, которое позволяет вам взаимодействовать с вашим компьютером с помощью голосовых команд на большинстве языков мира. Braina, помимо этого, точно преобразовывает речь в текст на более чем 100 разных языках мира.

История Голосовых Помощников

image

В последнее время голосовые помощники получили основную платформу после того, как Apple интегрировала самый удивительный Virtual Assistant — Siri, который официально является частью Apple Inc. Но график наибольшего развития начался с события 1962 года на выставке в Сиэтле, где IBM представила уникальный аппарат под названием Shoebox. Это был аппарат размером с обувную коробку, он мог выполнять научные функции и мог воспринимать 16 слов, а также произносить их человеческим узнаваемым голосом, и цифры от 0 до 9.

В течение 1970-х годов исследователи из Университета Карнеги-Меллона в Питтсбурге, штат Пенсильвания, при существенной помощи Министерства обороны США и его Агентства перспективных исследований в области обороны (DARPA), создали Harpy. Она могла понимать почти 1000 слов, что примерно соответствует словарному запасу трехлетнего ребенка.

Крупные организации, такие как Apple и IBM, рано, в 90-х годах, начали создавать вещи, использующие голосовое подтверждение. В 1993 году Macintosh начал создавать системы распознавания речи на своих компьютерах Macintosh с PlainTalk.

В апреле 1997 года Dragon NaturallySpeaking был первым продуктом с постоянной диктовкой, который мог охватить около 100 слов и преобразовать его в читаемый контент.

image

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

  • Открыть subreddit в браузере;
  • Открыть любой веб-сайт в браузере;
  • Отправить электронное письмо своим контактам;
  • Запустить любое системное приложение;
  • Сообщить текущую погоду и температуру любого города;
  • Сообщить текущее время;
  • Поприветствовать / завершить работу;
  • Воспроизвести песню на медиаплеере VLC (конечно, на вашем ноутбуке / настольном компьютере должен быть установлен медиаплеер VLC);
  • Изменить обои для рабочего стола;
  • Сообщить вам последние новости из новостной ленты;
  • Рассказать практически обо всем, что вы просите.

Итак, здесь, в этой статье, мы собираемся создать голосовое приложение, способное выполнять все вышеупомянутые задачи. Но сначала, посмотрите это видео, которое я сделал, когда общался со своим настольным голосовым помощником. И я зову ее София.

Надеюсь, вам, ребята, понравилось вышеупомянутое видео, в котором я общался с Софией. Теперь давайте начнем строить эту классную штуку.

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

Необходимые системные требования: Python 2.7, Spyder IDE, MacOS Mojave (версия 10.14)
Установите все эти библиотеки Python:

pip install SpeechRecognition
pip install beautifulsoup4
pip install vlc
pip install youtube-dl
pip install pyowm
pip install wikipedia

Давайте начнем создавать наш настольный голосовой помощник с Python

Начните с импорта всех необходимых библиотек:

import speech_recognition as sr
import os
import sys
import re
import webbrowser
import smtplib
import requests
import subprocess
from pyowm import OWM
import youtube_dl
import vlc
import urllib
import urllib2
import json
from bs4 import BeautifulSoup as soup
from urllib2 import urlopen
import wikipedia
import random
from time import strftime

Чтобы наш голосовой помощник выполнил все рассмотренные выше функции, мы должны закодировать логику каждой из них одним способом.

Итак, наш первый шаг — создать метод, который будет интерпретировать голосовой ответ пользователя:

def myCommand():
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print('Say something...')
        r.pause_threshold = 1
        r.adjust_for_ambient_noise(source, duration=1)
        audio = r.listen(source)
    try:
        command = r.recognize_google(audio).lower()
        print('You said: ' + command + 'n')
    #loop back to continue to listen for commands if unrecognizable speech is received
    except sr.UnknownValueError:
        print('....')
        command = myCommand();
    return command

Затем создайте метод, который будет преобразовывать текст в речь:

def sofiaResponse(audio):
    print(audio)
    for line in audio.splitlines():
        os.system("say " + audio)

Теперь создадим цикл, чтобы продолжить выполнение нескольких команд. Внутри метода assistant () передается пользовательская команда (myCommand ()) в качестве параметра:

while True:
    assistant(myCommand())

Наш следующий шаг — создать несколько операторов if, соответствующих каждой функции. Итак, давайте посмотрим, как создать эти небольшие модули внутри оператора if для каждой команды.

1. Открыть subreddit Reddit в браузере

Пользователь даст любую команду, чтобы открыть любой subreddit из Reddit, и команда должна быть «Эй, София! Можешь ли ты open Reddit subreddit_name».То, что выделено жирным курсивом следует использовать как есть. Вы можете использовать любой вид префикса, просто позаботьтесь о том, что выделено жирным.

Как это работает

Если вам удалось произвести open reddit в вашей команде, то она будет искать имя subreddit в пользовательской команде, используя re.search (). Субредит будет найден с помощью www.reddit.com и будет открыт в браузере с помощью модуля pythons Webbrowser. Модуль Webbrowser предоставляет высокоуровневый интерфейс, позволяющий отображать веб-документы для пользователей.

if 'open reddit' in command:
        reg_ex = re.search('open reddit (.*)', command)
        url = 'https://www.reddit.com/'
        if reg_ex:
            subreddit = reg_ex.group(1)
            url = url + 'r/' + subreddit
        webbrowser.open(url)
        sofiaResponse('The Reddit content has been opened for you Sir.')

Таким образом, приведенный выше код откроет нужный вам Reddit в браузере по умолчанию.

2. Открыть любой веб-сайт в браузере

Вы можете открыть любой веб-сайт, просто сказав «open website.com» или «open website.org».

Например: «Пожалуйста, открой facebook» или «Эй, вы можете открыть linkedin», так вы можете попросить Софию открыть любой веб-сайт.

Как это работает

Если вы сказали слово open в вашей команде, он будет искать имя веб-сайта в команде пользователя с помощью re.search (). Затем он добавит имя веб-сайта к https: // www. и используя модуль веб-браузера, далее полный URL-адрес открывается в браузере.

elif 'open' in command:
        reg_ex = re.search('open (.+)', command)
        if reg_ex:
            domain = reg_ex.group(1)
            print(domain)
            url = 'https://www.' + domain
            webbrowser.open(url)
            sofiaResponse('The website you have requested has been opened for you Sir.')
        else:
            pass

3. Отправить e-mail

Вы также можете попросить вашего настольного помощника отправить электронное письмо.

Как это работает

Если вы сказали слово email в своей команде, тогда бот спросит о получателе. Если мой ответ — rajat, бот будет использовать библиотеку pthons smtplib. Модуль smtplib определяет объект сеанса клиента SMTP, который можно использовать для отправки почты на любой компьютер Интернета с демоном прослушивателя SMTP или ESMTP. Отправка почты осуществляется с помощью smtplib Python с использованием SMTP-сервера. Сначала он инициирует SMTP gmail с помощью smtplib.SMTP (), затем идентифицирует сервер с помощью функции ehlo (), затем кодирует сеанс starttls (), затем входит в свой почтовый ящик с помощью login (), затем отправляет сообщение с помощью sendmail ().

elif 'email' in command:
        sofiaResponse('Who is the recipient?')
        recipient = myCommand()
if 'rajat' in recipient:
            sofiaResponse('What should I say to him?')
            content = myCommand()
            mail = smtplib.SMTP('smtp.gmail.com', 587)
            mail.ehlo()
            mail.starttls()
            mail.login('your_email_address', 'your_password')
            mail.sendmail('sender_email', 'receiver_email', content)
            mail.close()
            sofiaResponse('Email has been sent successfuly. You can check your inbox.')
else:
            sofiaResponse('I don't know what you mean!')

4. Запустить любое системное приложение

Скажите «Открой календарь» или «Можешь, пожалуйста, запустить Skype» или «София, открой Finder» и т.д. И София запустит для вас это системное приложение.

Как это работает

Если вы сказали слово «запуск» в своей команде, он будет искать имя приложения (если оно присутствует в вашей системе) в пользовательской команде, используя re.search (). Затем он добавит суффикс «.app» к имени приложения. Теперь ваше приложение называется, например, calender.app (в macOS исполняемые файлы заканчиваются расширением .app, в отличие от Windows, который заканчивается на .exe). Таким образом, имя исполняемого приложения будет запущено с использованием функции Popen () подпроцесса Python. Модуль подпроцесса позволяет запускать новые приложения из вашей программы Python.

elif 'launch' in command:
        reg_ex = re.search('launch (.*)', command)
        if reg_ex:
            appname = reg_ex.group(1)
            appname1 = appname+".app"
            subprocess.Popen(["open", "-n", "/Applications/" + appname1], stdout=subprocess.PIPE)
sofiaResponse('I have launched the desired application')

5. Сообщить текущую погоду и температуру любого города

София также может сказать вам погоду, максимальную и минимальную температуру любого города мира. Пользователь просто должен сказать что-то вроде «какая сейчас погода в Лондоне» или «скажи мне текущую погоду в Дели».

Как это работает

Если вы произнесли фразу текущей погоды в вашей команде, то она будет искать название города с помощью re.search (). Я использовал библиотеку pythons pyowm, чтобы узнать погоду в любом городе. get_status () расскажет вам о погодных условиях, таких как дымка, облачность, дождь и т. д., а get_tempera () расскажет о максимальной и минимальной температуре города.

elif 'current weather' in command:
     reg_ex = re.search('current weather in (.*)', command)
     if reg_ex:
         city = reg_ex.group(1)
         owm = OWM(API_key='ab0d5e80e8dafb2cb81fa9e82431c1fa')
         obs = owm.weather_at_place(city)
         w = obs.get_weather()
         k = w.get_status()
         x = w.get_temperature(unit='celsius')
         sofiaResponse('Current weather in %s is %s. The maximum temperature is %0.2f and the minimum temperature is %0.2f degree celcius' % (city, k, x['temp_max'], x['temp_min']))

6. Сообщить текущее время

«София, ты можешь сказать мне текущее время?» Или «Который сейчас час?», и София скажет вам текущее время вашего часового пояса.

Как это работает

Довольно просто

elif 'time' in command:
     import datetime
     now = datetime.datetime.now()
     sofiaResponse('Current time is %d hours %d minutes' % (now.hour, now.minute))

7. Приветствие / Завершение

Скажите «Здравствуй, София», чтобы поприветствовать своего голосового помощника, или, когда хотите, чтобы программа завершилась, произнесите что-то вроде «Заверши работу, София» или «София, пожалуйста, заверши работу» и т.д.

Как это работает

Если вы сказали слово «привет» в своей команде, то в зависимости от времени суток бот поприветствует пользователя. Если время больше 12 часов, бот ответит «Здравствуйте. Добрый день», а также, если время превышает 6 часов вечера, бот ответит «Здравствуйте. Добрый вечер». И когда вы даете команду как shutdown, вызывается sys.exit () для завершения программы.

#Greet Sofia
    elif 'hello' in command:
        day_time = int(strftime('%H'))
        if day_time < 12:
            sofiaResponse('Hello Sir. Good morning')
        elif 12 <= day_time < 18:
            sofiaResponse('Hello Sir. Good afternoon')
        else:
            sofiaResponse('Hello Sir. Good evening')
#to terminate the program
elif 'shutdown' in command:
     sofiaResponse('Bye bye Sir. Have a nice day')
     sys.exit()

8. Воспроизведение песни на медиаплеере VLC

Эта функция позволяет вашему голосовому боту воспроизводить желаемую песню в медиаплеере VLC. Пользователь скажет «София, сыграй мне песню», бот спросит: «Какую песню мне сыграть?». Просто скажите название песни, и София загрузит песню с youtube на ваш локальный диск, воспроизведите эту песню на медиаплеере VLC, и если вы снова воспроизведете песню, ранее загруженная песня будет автоматически удалена.

Как это работает

Если вы сказали, что эта фраза воспроизводит мне песню в вашей команде, то она спросит вас, какую видео песню играть. Песня, которую вы попросите, будет найдена на youtube.com. Если найденная песня будет загружена в ваш локальный каталог с помощью библиотеки pythons youtube_dl. Youtube-dl — это программа командной строки для загрузки видео с YouTube.com и нескольких других сайтов. Теперь песня будет воспроизводиться, как только она будет загружена с использованием библиотеки VLC pythons, и модуль play (path_to__videosong) фактически воспроизводит песню.

Теперь, если в следующий раз вы запросите любую другую песню, локальный каталог будет сброшен, и в этот каталог будет загружена новая песня.

elif 'play me a song' in command:
        path = '/Users/nageshsinghchauhan/Documents/videos/'
        folder = path
        for the_file in os.listdir(folder):
            file_path = os.path.join(folder, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
            except Exception as e:
                print(e)
sofiaResponse('What song shall I play Sir?')
mysong = myCommand()
        if mysong:
            flag = 0
            url = "https://www.youtube.com/results?search_query=" + mysong.replace(' ', '+')
            response = urllib2.urlopen(url)
            html = response.read()
            soup1 = soup(html,"lxml")
            url_list = []
            for vid in soup1.findAll(attrs={'class':'yt-uix-tile-link'}):
                if ('https://www.youtube.com' + vid['href']).startswith("https://www.youtube.com/watch?v="):
                    flag = 1
                    final_url = 'https://www.youtube.com' + vid['href']
                    url_list.append(final_url)
url = url_list[0]
            ydl_opts = {}
os.chdir(path)
            with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                ydl.download([url])
            vlc.play(path)
if flag == 0:
                sofiaResponse('I have not found anything in Youtube ')

9. Изменить обои для рабочего стола

Вы, также можете изменить обои для рабочего стола, используя эту функцию. Когда вы говорите что-то вроде «Поменять обои» или «София, пожалуйста, поменяй обои», бот загрузит случайные обои с unsplash.com и установит их в качестве фона рабочего стола.

Как это работает

Если вы сказали, что фраза изменяет обои в вашей команде, программа загрузит случайные обои с unsplash.com, сохранит их в локальном каталоге и установит их в качестве фонового рисунка рабочего стола, используя subprocess.call (). Я использовал unsplash API, чтобы получить доступ к его содержимому.

Теперь, если в следующий раз вы попросите изменить обои снова, ваш локальный каталог будет сброшен, и новые обои будут загружены в этот каталог.

elif 'change wallpaper' in command:
        folder = '/Users/nageshsinghchauhan/Documents/wallpaper/'
        for the_file in os.listdir(folder):
            file_path = os.path.join(folder, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
            except Exception as e:
                print(e)
        api_key = 'fd66364c0ad9e0f8aabe54ec3cfbed0a947f3f4014ce3b841bf2ff6e20948795'
        url = 'https://api.unsplash.com/photos/random?client_id=' + api_key #pic from unspalsh.com
        f = urllib2.urlopen(url)
        json_string = f.read()
        f.close()
        parsed_json = json.loads(json_string)
        photo = parsed_json['urls']['full']
        urllib.urlretrieve(photo, "/Users/nageshsinghchauhan/Documents/wallpaper/a") # Location where we download the image to.
        subprocess.call(["killall Dock"], shell=True)
        sofiaResponse('wallpaper changed successfully')

10. Сообщить последние новости из новостной ленты

София также может рассказать вам последние новости. Пользователь просто должен сказать «София, какие новости сегодня самые популярные?» Или «Скажите мне новости на сегодня».

Как это работает

Если вы произвели фразу «новости за сегодня» в своей команде, то она соскребет данные с помощью Beautiful Soup из RSS Новостей Google () и прочитает ее для вас. Для удобства я установил ограничение на количество новостей до 15.

elif 'news for today' in command:
        try:
            news_url="https://news.google.com/news/rss"
            Client=urlopen(news_url)
            xml_page=Client.read()
            Client.close()
            soup_page=soup(xml_page,"xml")
            news_list=soup_page.findAll("item")
            for news in news_list[:15]:
                sofiaResponse(news.title.text.encode('utf-8'))
        except Exception as e:
                print(e)

11. Рассказать практически обо всем, что вы спрашиваете

Ваш бот может получить подробную информацию практически обо всем, что вы у нее спросите. Например, «София расскажи мне о Google» или «Пожалуйста, расскажи мне о суперкомпьютерах» или «Пожалуйста, расскажи мне об Интернете». Итак, как вы можете видеть, вы можете спросить о чем угодно.

Как это работает

Если вы сказали фразу «расскажите мне» в своей команде, то она будет искать ключевое слово в пользовательской команде, используя re.search (). Используя библиотеку pythons wikipedia, она будет искать эту тему и извлекать первые 500 символов (если вы не укажете ограничение, бот будет читать всю страницу за вас). Википедия — это библиотека Python, которая позволяет легко получать и анализировать данные из Википедии.

elif 'tell me about' in command:
        reg_ex = re.search('tell me about (.*)', command)
        try:
            if reg_ex:
                topic = reg_ex.group(1)
                ny = wikipedia.page(topic)
                sofiaResponse(ny.content[:500].encode('utf-8'))
        except Exception as e:
                sofiaResponse(e)

Давайте сложим все вместе:

import speech_recognition as sr
import os
import sys
import re
import webbrowser
import smtplib
import requests
import subprocess
from pyowm import OWM
import youtube_dl
import vlc
import urllib
import urllib2
import json
from bs4 import BeautifulSoup as soup
from urllib2 import urlopen
import wikipedia
import random
from time import strftime
def sofiaResponse(audio):
    "speaks audio passed as argument"
    print(audio)
    for line in audio.splitlines():
        os.system("say " + audio)
def myCommand():
    "listens for commands"
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print('Say something...')
        r.pause_threshold = 1
        r.adjust_for_ambient_noise(source, duration=1)
        audio = r.listen(source)
    try:
        command = r.recognize_google(audio).lower()
        print('You said: ' + command + 'n')
    #loop back to continue to listen for commands if unrecognizable speech is received
    except sr.UnknownValueError:
        print('....')
        command = myCommand();
    return command
def assistant(command):
    "if statements for executing commands"
#open subreddit Reddit
    if 'open reddit' in command:
        reg_ex = re.search('open reddit (.*)', command)
        url = 'https://www.reddit.com/'
        if reg_ex:
            subreddit = reg_ex.group(1)
            url = url + 'r/' + subreddit
        webbrowser.open(url)
        sofiaResponse('The Reddit content has been opened for you Sir.')
elif 'shutdown' in command:
        sofiaResponse('Bye bye Sir. Have a nice day')
        sys.exit()
#open website
    elif 'open' in command:
        reg_ex = re.search('open (.+)', command)
        if reg_ex:
            domain = reg_ex.group(1)
            print(domain)
            url = 'https://www.' + domain
            webbrowser.open(url)
            sofiaResponse('The website you have requested has been opened for you Sir.')
        else:
            pass
#greetings
    elif 'hello' in command:
        day_time = int(strftime('%H'))
        if day_time < 12:
            sofiaResponse('Hello Sir. Good morning')
        elif 12 <= day_time < 18:
            sofiaResponse('Hello Sir. Good afternoon')
        else:
            sofiaResponse('Hello Sir. Good evening')
elif 'help me' in command:
        sofiaResponse("""
        You can use these commands and I'll help you out:
1. Open reddit subreddit : Opens the subreddit in default browser.
        2. Open xyz.com : replace xyz with any website name
        3. Send email/email : Follow up questions such as recipient name, content will be asked in order.
        4. Current weather in {cityname} : Tells you the current condition and temperture
        5. Hello
        6. play me a video : Plays song in your VLC media player
        7. change wallpaper : Change desktop wallpaper
        8. news for today : reads top news of today
        9. time : Current system time
        10. top stories from google news (RSS feeds)
        11. tell me about xyz : tells you about xyz
        """)
#joke
    elif 'joke' in command:
        res = requests.get(
                'https://icanhazdadjoke.com/',
                headers={"Accept":"application/json"})
        if res.status_code == requests.codes.ok:
            sofiaResponse(str(res.json()['joke']))
        else:
            sofiaResponse('oops!I ran out of jokes')
#top stories from google news
    elif 'news for today' in command:
        try:
            news_url="https://news.google.com/news/rss"
            Client=urlopen(news_url)
            xml_page=Client.read()
            Client.close()
            soup_page=soup(xml_page,"xml")
            news_list=soup_page.findAll("item")
            for news in news_list[:15]:
                sofiaResponse(news.title.text.encode('utf-8'))
        except Exception as e:
                print(e)
#current weather
    elif 'current weather' in command:
        reg_ex = re.search('current weather in (.*)', command)
        if reg_ex:
            city = reg_ex.group(1)
            owm = OWM(API_key='ab0d5e80e8dafb2cb81fa9e82431c1fa')
            obs = owm.weather_at_place(city)
            w = obs.get_weather()
            k = w.get_status()
            x = w.get_temperature(unit='celsius')
            sofiaResponse('Current weather in %s is %s. The maximum temperature is %0.2f and the minimum temperature is %0.2f degree celcius' % (city, k, x['temp_max'], x['temp_min']))
#time
    elif 'time' in command:
        import datetime
        now = datetime.datetime.now()
        sofiaResponse('Current time is %d hours %d minutes' % (now.hour, now.minute))
elif 'email' in command:
        sofiaResponse('Who is the recipient?')
        recipient = myCommand()
        if 'rajat' in recipient:
            sofiaResponse('What should I say to him?')
            content = myCommand()
            mail = smtplib.SMTP('smtp.gmail.com', 587)
            mail.ehlo()
            mail.starttls()
            mail.login('your_email_address', 'your_password')
            mail.sendmail('sender_email', 'receiver_email', content)
            mail.close()
            sofiaResponse('Email has been sent successfuly. You can check your inbox.')
        else:
            sofiaResponse('I don't know what you mean!')
#launch any application
    elif 'launch' in command:
        reg_ex = re.search('launch (.*)', command)
        if reg_ex:
            appname = reg_ex.group(1)
            appname1 = appname+".app"
            subprocess.Popen(["open", "-n", "/Applications/" + appname1], stdout=subprocess.PIPE)
sofiaResponse('I have launched the desired application')
#play youtube song
    elif 'play me a song' in command:
        path = '/Users/nageshsinghchauhan/Documents/videos/'
        folder = path
        for the_file in os.listdir(folder):
            file_path = os.path.join(folder, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
            except Exception as e:
                print(e)
sofiaResponse('What song shall I play Sir?')
        mysong = myCommand()
        if mysong:
            flag = 0
            url = "https://www.youtube.com/results?search_query=" + mysong.replace(' ', '+')
            response = urllib2.urlopen(url)
            html = response.read()
            soup1 = soup(html,"lxml")
            url_list = []
            for vid in soup1.findAll(attrs={'class':'yt-uix-tile-link'}):
                if ('https://www.youtube.com' + vid['href']).startswith("https://www.youtube.com/watch?v="):
                    flag = 1
                    final_url = 'https://www.youtube.com' + vid['href']
                    url_list.append(final_url)
url = url_list[0]
            ydl_opts = {}
os.chdir(path)
            with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                ydl.download([url])
            vlc.play(path)
if flag == 0:
                sofiaResponse('I have not found anything in Youtube ')
#change wallpaper
    elif 'change wallpaper' in command:
        folder = '/Users/nageshsinghchauhan/Documents/wallpaper/'
        for the_file in os.listdir(folder):
            file_path = os.path.join(folder, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
            except Exception as e:
                print(e)
        api_key = 'fd66364c0ad9e0f8aabe54ec3cfbed0a947f3f4014ce3b841bf2ff6e20948795'
        url = 'https://api.unsplash.com/photos/random?client_id=' + api_key #pic from unspalsh.com
        f = urllib2.urlopen(url)
        json_string = f.read()
        f.close()
        parsed_json = json.loads(json_string)
        photo = parsed_json['urls']['full']
        urllib.urlretrieve(photo, "/Users/nageshsinghchauhan/Documents/wallpaper/a") # Location where we download the image to.
        subprocess.call(["killall Dock"], shell=True)
        sofiaResponse('wallpaper changed successfully')
#askme anything
    elif 'tell me about' in command:
        reg_ex = re.search('tell me about (.*)', command)
        try:
            if reg_ex:
                topic = reg_ex.group(1)
                ny = wikipedia.page(topic)
                sofiaResponse(ny.content[:500].encode('utf-8'))
        except Exception as e:
                print(e)
                sofiaResponse(e)
sofiaResponse('Hi User, I am Sofia and I am your personal voice assistant, Please give a command or say "help me" and I will tell you what all I can do for you.')
#loop to continue executing multiple commands
while True:
    assistant(myCommand())

Итак, вы видели, как, просто написав простые строки кода на Python, мы можем создать очень классного голосового помощника для компьютера. Помимо этих функций, вы также можете включить множество различных функций в свой голосовой помощник.

Вывод

Что ждет нас в будущем, на протяжении всей истории вычислений пользовательские интерфейсы стали все более естественными в использовании. Экран и клавиатура были одним шагом в этом направлении. Мышь и графический интерфейс пользователя были другими. Сенсорные экраны являются самой последней разработкой. Следующий шаг, скорее всего, будет состоять из смеси дополненной реальности, жестов и голосовых команд. В конце концов, часто легче задать вопрос или поговорить, чем набрать что-то или ввести несколько деталей в онлайн-форме.

Чем больше человек взаимодействует с устройствами, активируемыми голосом, тем больше трендов и паттернов, которые система идентифицирует на основе получаемой информации. Затем эти данные можно использовать для определения пользовательских предпочтений и вкусов, что является долгосрочным преимуществом для того, чтобы сделать дом умнее. Google и Amazon стремятся интегрировать голосовой искусственный интеллект, способный анализировать человеческие эмоции и реагировать на них.

Надеюсь, вам понравилось читать эту статью. Поделитесь своими мыслями/комментариями/сомнениями в разделе комментариев.

Всем знаний!

Вы когда-нибудь задумывались, как здорово было бы иметь своего собственного ИИ-ассистента (типа Д.Ж.А.Р.В.И.С.)? Было бы гораздо легче отправлять письма, искать информацию в Википедии, не открывая браузер, и выполнять ещё много других действий с помощью одного только голоса.

В этом уроке мы узнаем, как написать код собственного голосового помощника на Python.

Перед тем, как начать, мы должны определиться, какими функциями должен обладать наш голосовой помощник:

  • Отправка электронных писем
  • Воспроизведение музыки
  • Запросы в Википедию
  • Открытие сайтов, таких как Google, YouTube, Stackoverflow, freecodecamp и т.д. в браузере
  • Открытие редактора кода или IDE одной голосовой командой

И всё это без ручного ввода запросов в браузере!

А теперь приступим, собственно, к написанию нашего помощника.

И да: не забудьте сперва придумать ему имя :з

Настройка среды

Я использую PyCharm, но вы можете выбрать абсолютно любой удобный вам редактор.

Сперва мы импортируем/установим все необходимые библиотеки:

  • pyttsx3;
  • datetime;
  • speech recognition;
  • wikipedia;
  • webbrowser;
  • os.path;
  • smtplib.

Определение функции воспроизведения речи

Интеллектуальному голосовому помощнику прежде всего полагается говорить. Чтобы бот говорил, мы определим функцию speak(), которая принимает на входе аудио и произносит его.

def speak(audio): pass #пока так, позже мы напишем все условия.

Теперь нам нужно аудио, чтобы обеспечить коммуникацию пользователя и ассистента. Для этого мы установим модуль pyttsx3.

Что такое pyttsx3?

Это библиотека Python, которая поможет нам конвертировать текст в устную речь. Она работает оффлайн и доступна как для Python 3, так и для Python 2.

Установка:

pip install pyttsx3

После успешной установки pyttsx3 нужно импортировать модуль в нашу программу.

Использование:

import pyttsx3

engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices') #даёт подробности о текущем установленном голосе
engine.setProperty('voice', voice[1].id)  # 0-мужской , 1-женский

Что такое sapi5? Microsoft Speech API (SAPI5) – технология для распознавания и синтеза речи, предоставленная Microsoft.

VoiceId помогает нам выбирать разные голоса:

  • voice[0].idмужской голос
  • voice[1].id = женский голос

[python_ad_block]

Создание функции speak()

def speak(audio):   
engine.say(audio)    
engine.runAndWait() #Без этой команды мы не услышим речь

Создание функции main()

Теперь определим функцию main() и вызовем функцию speak() внутри неё.

if __name__=="__main__" :

speak('Hello Sir, I am Friday, your Artificial intelligence assistant. Please tell me how may I help you')

P.S. Я назову своего ассистента Friday (Пятница).

Всё, что вы передадите функции speak(), будет полностью преобразовано в звук. Поздравляю: наш голосовой помощник обрел свой голос и готов с нами болтать!

Создание функции wishme()

Теперь мы напишем функцию wishme(), благодаря которой наш голосовой помощник будет приветствовать нас разными способами в зависимости от времени на компьютере.

Чтобы предоставить нашему ассистенту информацию о времени, мы должны импортировать модуль datetime, делается это следующей командой:

import datetime

Теперь напишем функцию wishme():

def wishme():
   hour = int(datetime.datetime.now().hour)

Здесь мы сохраняем целочисленное значение текущего часа в переменную hour. Используем это значение в конструкции if-else:

def wishMe():
    hour = int(datetime.datetime.now().hour)
    if hour>=0 and hour<12:
        speak("Good Morning!")    
    
    elif hour>=12 and hour<18:
        speak("Good Afternoon!")       
    
    else:
        speak("Good Evening!")      
   
   speak('Hello Sir, I am Friday, your Artificial intelligence assistant. Please tell me how may I help you')

Определение функции takeCommand():

Следующий важный аспект в нашем помощнике: он должен уметь принимать команду с помощью микрофона нашей системы. Для этого мы создадим функцию takeCommand().

С помощью takeCommand() наш интеллектуальный ассистент сможет возвращать строку, принимая голосовые команды по микрофону.

Но перед определением takeCommand() мы должны установить модуль speechRecognition следующей командой:

pip install speechRecognition

После установки импортируем модуль в программу:

import speechRecognition as sr

Начнём написание функции takeCommand() :

def takeCommand():
    #Принимает на входе аудио от микрофона, возвращает строку с нашими словами    
     r = sr.Recognizer()
     with sr.Microphone() as source:
         print("Listening...")
         r.pause_threshold = 1
         audio = r.listen(source)

Мы успешно создали нашу функцию takeCommand(). Также мы добавим блок try-except для обработки ошибок.

try:
        print("Recognizing...")    
        query = r.recognize_google(audio, language='en-in') #Используем google для распознания голоса.
        print(f"User said: {query}n")  #Запрос пользователя выведен.    
except Exception as e:
        # print(e)  используйте только если хотите видеть ошибку!
        print("Say that again please...")   #будет выведено, если речь не распознаётся
        return "None" #вернётся строка "Пусто"
    return query

А теперь мы наконец-то можем приступить к определению задач для получения необходимой информации.

Задача 1: поиск по Википедии

Чтобы отправлять поисковые запросы в Википедию, мы должны установить и импортировать в нашу программу модуль wikipedia.

Команда для установки:

pip install wikipedia

После установки используем import, чтобы добавить модуль в программу:

if __name__ == "__main__":
    wishMe()
    while True:
        query = takeCommand().lower() #Приведём запрос к нижему регистру        
        # выполнение задач в соответствии с запросом
        if 'wikipedia' in query:  #если wikipedia встречается в запросе, выполнится блок:
            speak('Searching Wikipedia...')
            query = query.replace("wikipedia", "")
            results = wikipedia.summary(query, sentences=5) 
            speak("According to Wikipedia")
            print(results)
            speak(results)

В коде выше мы использовали if, чтобы проверить, есть ли в запросе пользователя слово «Википедия». Если слово присутствует, помощник прочитает и озвучит с помощью speak() первые 5 предложений из статьи в Википедии (можно поменять число предложений на любое другое).

Задача 2: открыть YouTube в браузере

Для открытия сайтов мы используем модуль webbrowser.

Это встроенный модуль, так что устанавливать его нам не придётся. Остаётся лишь импортировать его.

Код:

elif 'open youtube' in query:
    webbrowser.open("youtube.com")

Здесь мы используем elif, чтобы проверить наличие «YouTube» в запросе. Предположим, что пользователь даёт команду «Открой YouTube». В этом случае условие в elif выполнится и код будет исполнен.

Задача 3: открыть Google-поиск в браузере

elif 'open google' in query:
    webbrowser.open("google.com")

Открытие Google происходит по той же логике, что и с YouTube.

Задача 4: воспроизвести музыку

Чтобы проигрывать музыку, нужно импортировать модуль os:

elif 'play music' in query:
    music_dir = 'директория_с_музыкой'
    songs = os.listdir(music_dir)
    print(songs)    
    os.startfile(os.path.join(music_dir, songs[0]))

В данном коде мы в первую очередь открываем директорию с музыкой пользователя и перечисляем все песни в директории с помощью модуля os.

os.startfile позволяет нам воспроизвести любую нашу песню. Также можно включить случайно выбранную композицию с помощью модуля random. Каждый раз, когда вы будете просить включить музыку, голосовой помощник будет запускать воспроизведение любой песни из указанной папки.

Задача 5: узнать время

elif 'the time' in query:
    strTime = datetime.datetime.now().strftime("%H:%M:%S")    
    speak(f"Sir, the time is {strTime}")

В этом коде мы используем функцию datetime() и сохраняем текущее время в переменной strTime.

После сохранения времени в strTime мы передаем переменную в качестве аргумента в функцию speak(), чтобы там она превратилась в речь.

Задача 6: открыть StackOverflow

elif 'open stack overflow' in query :                           
    webbrowser.open('stackoverflow.com')

Делаем то же самое, что и в случае с Google/Youtube.

Задача 7: открыть freecodecamp

elif 'open free code camp' in query :            
    webbrowser.open('freecodecamp.org')

Делаем то же самое, что и в случае с Google/Youtube.

Задача 8: открыть PyCharm (или другую IDE):

elif 'open code' in query:
    codePath = "/Applications/PyCharm CE.app" #путь к приложению
    os.startfile(codePath)

Чтобы открыть PyCharm или любое другое приложение, нужно указать путь к нему.

Задача 9: отправить email

Чтобы послать электронное письмо, мы импортируем модуль smtplib.

Simple Mail Transfer Protocol (SMTP) — протокол, позволяющий нам отправлять электронные письма и маршрутизировать электронные письма между разными почтовыми серверами.

Метод sendmail представлен в модуле SMTP. Именно этот метод позволяет отправлять письма.

Он принимает 3 параметра:

  • sender: email-адрес отправителя.
  • receiver: email-адрес получателя.
  • message:  строка с сообщением, которую нужно отправить одному или нескольким адресатам.

Теперь мы можем создать функцию sendEmail(), которой мы будем посылать письма.

def sendEmail(to, content):
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login('youremail@gmail.com', 'пароль')
    server.sendmail('youremail@gmail.com', 'кому', 'содержание')
    server.close()

Замечание: не забудьте включить опцию ‘ненадёжные приложения, у которых есть доступ к аккаунту’ в вашем Gmail-аккаунте. Иначе функция sendEmail не сработает нужным образом.

Вызываем sendEmail() внутри main():

elif 'email to receiver's name' in query:
    try:
        speak("What should I say?")
        content = takeCommand()
        to = "receiver's email id"    
        sendEmail(to, content)
        speak("Email has been sent!")
    except Exception as e:
        print(e)
        speak("Sorry sir. I am not able to send this email")

Мы используем блок try-except, чтобы обрабатывать все ошибки, которые могут произойти при отправлении писем.

Повторяем изученное

  • Сначала мы создали функцию wishme(), которая предоставляет функционал для приветствия пользователя в соответствии с системным временем.
  • После wishme() мы создали функцию takeCommand(), которая позволяет ассистенту принимать команды пользователя и действовать в соответствии с ними. Эта функция возвращает запрос пользователя в формате строки.
  • Мы проработали логику для открывания различных сайтов: Google, YouTube, Stackoverflow, freecodecamp, Wikipedia.
  • Мы также добавили возможность открывать IDE PyCharm и другие приложения.
  • В конце мы разработали функцию отправки электронных писем (без написания единого слова, разве не круто?)

И тут последует самый противоречивый вопрос…

Можно ли считать это искусственным интеллектом?

Технически нет, ведь этот помощник – всего лишь результат выполнения набора команд. Но если поподробнее разобраться в вопросе, можно узнать, что цель любого ИИ – просто облегчить человеческую работу, выполняя задания с эффективностью человека (или даже лучше).

А наш голосовой помощник в значительной степени решает эту задачу.

Так что финальный вердикт: это ИИ!

Конец!

Мои поздравления: мы успешно создали нашего личного голосового помощника и сделали ещё один шаг навстречу нашей лени!

Надеюсь, статья вам понравилась!

Чтобы лучше понять код, можно зайти в репозиторий автора на GitHub.

Перевод статьи «A guide to your own A.I. Voice Assistant using Python !!».

Voice Assistant Python App for Windows, Linux & MacOS

Возможности приложения

Данный проект голосового ассистента на Python 3 для Windows и Linux умеет:

  • распознавать и синтезировать речь в offline-режиме (без доступа к Интернету);
  • сообщать о прогнозе погоды в любой точке мира;
  • производить поисковый запрос в поисковой системе Google
    (а также открывать список результатов и сами результаты данного запроса);
  • производить поисковый запрос видео в системе YouTube и открывать список результатов данного запроса;
  • выполнять поиск определения в Wikipedia c дальнейшим прочтением первых двух предложений;
  • переводить с изучаемого языка на родной язык пользователя (с учетом особенностей воспроизведения речи);
  • искать человека по имени и фамилии в соцсетях ВКонтакте и Facebook;
  • «подбрасывать монетку»;
  • воспроизводить случайное приветствие;
  • воспроизводить случайное прощание с последующим завершением работы программы;
  • менять настройки языка распознавания и синтеза речи;
  • TODO многое другое…

Для быстрой установки всех требуемых зависимостей можно воспользоваться командой:

pip install requirements.txt

Настройка синтеза и анализа речи с возможностью offline-работы

Голосовой ассистент использует для синтеза речи встроенные в операционные системы возможности
(т.е. голоса зависят от настроек операционной системы). Для этого используется библиотека pyttsx3. Подробнее здесь

Для корректной работы системы распознавания речи в сочетании с библиотекой SpeechRecognition
используется библиотека PyAudio для получения звука с микрофона.

В целом, решение работает на Windows, Linux и MacOS с незначительными различиями при установке библиотек PyAudio и Google.

Для установки PyAudio на Windows можно найти и скачать нужный в зависимости от архитектуры и версии Python whl-файл здесь в папку с проектом. После чего его можно установить при помощи подобной команды:

pip install PyAudio-0.2.11-cp38-cp38m-win_amd64.whl

В случае проблем с установкой PyAudio на MacOS может помочь данное решение.

Для использования SpeechRecognition в offline-режиме (без доступа к Интернету), 
потребуется дополнительно установить Vosk (качество моделей близко к Google)

В проекте преимущественно используется Google при наличии доступа в Интернет и
предусмотрено переключение на Vosk в случае отсутствия доступа к сети.

Для избежания проблем с установкой Vosk на Windows, я предлагаю скачать whl-файл в зависимости от требуемой архитектуры и версии Python. Его можно найти здесь. Загрузив файл в папку с проектом, установку можно будет запустить с помощью подобной команды:

pip install vosk-0.3.7-cp38-cp38-win_amd64.whl

Модели для распознавания речи с помощью Vosk можно найти здесь. Я использовала в проекте ru и en модели

Настройка получения прогноза погоды от OpenWeatherMap

Для получения данных прогноза погоды мною был использован сервис OpenWeatherMap, который требует API-ключ.
Получить API-ключ и ознакомиться с документацией можно после регистрации (есть Free-тариф) здесь.
Примеры использования можно найти здесь

Прочие зависимости

Команды для установки прочих сторонних библиотек:

Команда установки Назначение библиотеки
pip install google Поисковые запросы в Google
pip install SpeechRecognition Распознавание речи (Speech-To-Text)
pip install vosk Offline распознавание речи (Speech-To-Text)
pip install pyttsx3 Offline синтез речи на Windows (Text-To-Speech)
pip install wikipedia-api Wikipedia API
pip install googletrans Google Translate
pip install pyowm Получение данных погоды с помощью OpenWeatherMap
pip install python-dotenv Работа с .env-файлами для хранения API-ключей
pip install scikit-learn Машинного обучение для угадывания намерений

Дополнительную информацию по установке и использованию библиотек можно найти здесь

У меня на Windows не возникало проблем с установкой библиотек, перечисленных в таблице выше, 
потому прилагаю только команды для установки.

В случае возникновения проблем с установкой на Windows, вы можете воспользоваться тем же способом, 
который я предлагала для установки PyAudio выше.

if __name__ == '__main__':

    clear = lambda: os.system('cls')

    clear()

    wishMe()

    username()

    while True:

        query = takeCommand().lower()

        if 'wikipedia' in query:

            speak('Searching Wikipedia...')

            query = query.replace("wikipedia", "")

            results = wikipedia.summary(query, sentences = 3)

            speak("According to Wikipedia")

            print(results)

            speak(results)

        elif 'open youtube' in query:

            speak("Here you go to Youtuben")

            webbrowser.open("youtube.com")

        elif 'open google' in query:

            speak("Here you go to Googlen")

            webbrowser.open("google.com")

        elif 'open stackoverflow' in query:

            speak("Here you go to Stack Over flow.Happy coding")

            webbrowser.open("stackoverflow.com")  

        elif 'play music' in query or "play song" in query:

            speak("Here you go with music")

            music_dir = "C:\Users\GAURAV\Music"

            songs = os.listdir(music_dir)

            print(songs)   

            random = os.startfile(os.path.join(music_dir, songs[1]))

        elif 'the time' in query:

            strTime = datetime.datetime.now().strftime("% H:% M:% S")   

            speak(f"Sir, the time is {strTime}")

        elif 'open opera' in query:

            codePath = r"C:\Users\GAURAV\AppData\Local\Programs\Opera\launcher.exe"

            os.startfile(codePath)

        elif 'email to gaurav' in query:

            try:

                speak("What should I say?")

                content = takeCommand()

                to = "Receiver email address"   

                sendEmail(to, content)

                speak("Email has been sent !")

            except Exception as e:

                print(e)

                speak("I am not able to send this email")

        elif 'send a mail' in query:

            try:

                speak("What should I say?")

                content = takeCommand()

                speak("whome should i send")

                to = input()   

                sendEmail(to, content)

                speak("Email has been sent !")

            except Exception as e:

                print(e)

                speak("I am not able to send this email")

        elif 'how are you' in query:

            speak("I am fine, Thank you")

            speak("How are you, Sir")

        elif 'fine' in query or "good" in query:

            speak("It's good to know that your fine")

        elif "change my name to" in query:

            query = query.replace("change my name to", "")

            assname = query

        elif "change name" in query:

            speak("What would you like to call me, Sir ")

            assname = takeCommand()

            speak("Thanks for naming me")

        elif "what's your name" in query or "What is your name" in query:

            speak("My friends call me")

            speak(assname)

            print("My friends call me", assname)

        elif 'exit' in query:

            speak("Thanks for giving me your time")

            exit()

        elif "who made you" in query or "who created you" in query:

            speak("I have been created by Gaurav.")

        elif 'joke' in query:

            speak(pyjokes.get_joke())

        elif "calculate" in query:

            app_id = "Wolframalpha api id"

            client = wolframalpha.Client(app_id)

            indx = query.lower().split().index('calculate')

            query = query.split()[indx + 1:]

            res = client.query(' '.join(query))

            answer = next(res.results).text

            print("The answer is " + answer)

            speak("The answer is " + answer)

        elif 'search' in query or 'play' in query:

            query = query.replace("search", "")

            query = query.replace("play", "")         

            webbrowser.open(query)

        elif "who i am" in query:

            speak("If you talk then definitely your human.")

        elif "why you came to world" in query:

            speak("Thanks to Gaurav. further It's a secret")

        elif 'power point presentation' in query:

            speak("opening Power Point presentation")

            power = r"C:\Users\GAURAV\Desktop\Minor Project\Presentation\Voice Assistant.pptx"

            os.startfile(power)

        elif 'is love' in query:

            speak("It is 7th sense that destroy all other senses")

        elif "who are you" in query:

            speak("I am your virtual assistant created by Gaurav")

        elif 'reason for you' in query:

            speak("I was created as a Minor project by Mister Gaurav ")

        elif 'change background' in query:

            ctypes.windll.user32.SystemParametersInfoW(20,

                                                       0,

                                                       "Location of wallpaper",

                                                       0)

            speak("Background changed successfully")

        elif 'open bluestack' in query:

            appli = r"C:\ProgramData\BlueStacks\Client\Bluestacks.exe"

            os.startfile(appli)

        elif 'news' in query:

            try:

                jsonObj = urlopen()

                data = json.load(jsonObj)

                i = 1

                speak('here are some top news from the times of india')

                print(+ 'n')

                for item in data['articles']:

                    print(str(i) + '. ' + item['title'] + 'n')

                    print(item['description'] + 'n')

                    speak(str(i) + '. ' + item['title'] + 'n')

                    i += 1

            except Exception as e:

                print(str(e))

        elif 'lock window' in query:

                speak("locking the device")

                ctypes.windll.user32.LockWorkStation()

        elif 'shutdown system' in query:

                speak("Hold On a Sec ! Your system is on its way to shut down")

                subprocess.call('shutdown / p /f')

        elif 'empty recycle bin' in query:

            winshell.recycle_bin().empty(confirm = False, show_progress = False, sound = True)

            speak("Recycle Bin Recycled")

        elif "don't listen" in query or "stop listening" in query:

            speak("for how much time you want to stop jarvis from listening commands")

            a = int(takeCommand())

            time.sleep(a)

            print(a)

        elif "where is" in query:

            query = query.replace("where is", "")

            location = query

            speak("User asked to Locate")

            speak(location)

        elif "camera" in query or "take a photo" in query:

            ec.capture(0, "Jarvis Camera ", "img.jpg")

        elif "restart" in query:

            subprocess.call(["shutdown", "/r"])

        elif "hibernate" in query or "sleep" in query:

            speak("Hibernating")

            subprocess.call("shutdown / h")

        elif "log off" in query or "sign out" in query:

            speak("Make sure all the application are closed before sign-out")

            time.sleep(5)

            subprocess.call(["shutdown", "/l"])

        elif "write a note" in query:

            speak("What should i write, sir")

            note = takeCommand()

            file = open('jarvis.txt', 'w')

            speak("Sir, Should i include date and time")

            snfm = takeCommand()

            if 'yes' in snfm or 'sure' in snfm:

                strTime = datetime.datetime.now().strftime("% H:% M:% S")

                file.write(strTime)

                file.write(" :- ")

                file.write(note)

            else:

                file.write(note)

        elif "show note" in query:

            speak("Showing Notes")

            file = open("jarvis.txt", "r")

            print(file.read())

            speak(file.read(6))

        elif "update assistant" in query:

            speak("After downloading file please replace this file with the downloaded one")

            url = '# url after uploading file'

            r = requests.get(url, stream = True)

            with open("Voice.py", "wb") as Pypdf:

                total_length = int(r.headers.get('content-length'))

                for ch in progress.bar(r.iter_content(chunk_size = 2391975),

                                       expected_size =(total_length / 1024) + 1):

                    if ch:

                      Pypdf.write(ch)

        elif "jarvis" in query:

            wishMe()

            speak("Jarvis 1 point o in your service Mister")

            speak(assname)

        elif "weather" in query:

            api_key = "Api key"

            speak(" City name ")

            print("City name : ")

            city_name = takeCommand()

            complete_url = base_url + "appid =" + api_key + "&q =" + city_name

            response = requests.get(complete_url)

            x = response.json()

            if x["code"] != "404":

                y = x["main"]

                current_temperature = y["temp"]

                current_pressure = y["pressure"]

                current_humidiy = y["humidity"]

                z = x["weather"]

                weather_description = z[0]["description"]

                print(" Temperature (in kelvin unit) = " +str(current_temperature)+"n atmospheric pressure (in hPa unit) ="+str(current_pressure) +"n humidity (in percentage) = " +str(current_humidiy) +"n description = " +str(weather_description))

            else:

                speak(" City Not Found ")

        elif "send message " in query:

                account_sid = 'Account Sid key'

                auth_token = 'Auth token'

                client = Client(account_sid, auth_token)

                message = client.messages

                                .create(

                                    body = takeCommand(),

                                    from_='Sender No',

                                    to ='Receiver No'

                                )

                print(message.sid)

        elif "wikipedia" in query:

            webbrowser.open("wikipedia.com")

        elif "Good Morning" in query:

            speak("A warm" +query)

            speak("How are you Mister")

            speak(assname)

        elif "will you be my gf" in query or "will you be my bf" in query:  

            speak("I'm not sure about, may be you should give me some time")

        elif "how are you" in query:

            speak("I'm fine, glad you me that")

        elif "i love you" in query:

            speak("It's hard to understand")

        elif "what is" in query or "who is" in query:

            client = wolframalpha.Client("API_ID")

            res = client.query(query)

            try:

                print (next(res.results).text)

                speak (next(res.results).text)

            except StopIteration:

                print ("No results")

if __name__ == '__main__':

    clear = lambda: os.system('cls')

    clear()

    wishMe()

    username()

    while True:

        query = takeCommand().lower()

        if 'wikipedia' in query:

            speak('Searching Wikipedia...')

            query = query.replace("wikipedia", "")

            results = wikipedia.summary(query, sentences = 3)

            speak("According to Wikipedia")

            print(results)

            speak(results)

        elif 'open youtube' in query:

            speak("Here you go to Youtuben")

            webbrowser.open("youtube.com")

        elif 'open google' in query:

            speak("Here you go to Googlen")

            webbrowser.open("google.com")

        elif 'open stackoverflow' in query:

            speak("Here you go to Stack Over flow.Happy coding")

            webbrowser.open("stackoverflow.com")  

        elif 'play music' in query or "play song" in query:

            speak("Here you go with music")

            music_dir = "C:\Users\GAURAV\Music"

            songs = os.listdir(music_dir)

            print(songs)   

            random = os.startfile(os.path.join(music_dir, songs[1]))

        elif 'the time' in query:

            strTime = datetime.datetime.now().strftime("% H:% M:% S")   

            speak(f"Sir, the time is {strTime}")

        elif 'open opera' in query:

            codePath = r"C:\Users\GAURAV\AppData\Local\Programs\Opera\launcher.exe"

            os.startfile(codePath)

        elif 'email to gaurav' in query:

            try:

                speak("What should I say?")

                content = takeCommand()

                to = "Receiver email address"   

                sendEmail(to, content)

                speak("Email has been sent !")

            except Exception as e:

                print(e)

                speak("I am not able to send this email")

        elif 'send a mail' in query:

            try:

                speak("What should I say?")

                content = takeCommand()

                speak("whome should i send")

                to = input()   

                sendEmail(to, content)

                speak("Email has been sent !")

            except Exception as e:

                print(e)

                speak("I am not able to send this email")

        elif 'how are you' in query:

            speak("I am fine, Thank you")

            speak("How are you, Sir")

        elif 'fine' in query or "good" in query:

            speak("It's good to know that your fine")

        elif "change my name to" in query:

            query = query.replace("change my name to", "")

            assname = query

        elif "change name" in query:

            speak("What would you like to call me, Sir ")

            assname = takeCommand()

            speak("Thanks for naming me")

        elif "what's your name" in query or "What is your name" in query:

            speak("My friends call me")

            speak(assname)

            print("My friends call me", assname)

        elif 'exit' in query:

            speak("Thanks for giving me your time")

            exit()

        elif "who made you" in query or "who created you" in query:

            speak("I have been created by Gaurav.")

        elif 'joke' in query:

            speak(pyjokes.get_joke())

        elif "calculate" in query:

            app_id = "Wolframalpha api id"

            client = wolframalpha.Client(app_id)

            indx = query.lower().split().index('calculate')

            query = query.split()[indx + 1:]

            res = client.query(' '.join(query))

            answer = next(res.results).text

            print("The answer is " + answer)

            speak("The answer is " + answer)

        elif 'search' in query or 'play' in query:

            query = query.replace("search", "")

            query = query.replace("play", "")         

            webbrowser.open(query)

        elif "who i am" in query:

            speak("If you talk then definitely your human.")

        elif "why you came to world" in query:

            speak("Thanks to Gaurav. further It's a secret")

        elif 'power point presentation' in query:

            speak("opening Power Point presentation")

            power = r"C:\Users\GAURAV\Desktop\Minor Project\Presentation\Voice Assistant.pptx"

            os.startfile(power)

        elif 'is love' in query:

            speak("It is 7th sense that destroy all other senses")

        elif "who are you" in query:

            speak("I am your virtual assistant created by Gaurav")

        elif 'reason for you' in query:

            speak("I was created as a Minor project by Mister Gaurav ")

        elif 'change background' in query:

            ctypes.windll.user32.SystemParametersInfoW(20,

                                                       0,

                                                       "Location of wallpaper",

                                                       0)

            speak("Background changed successfully")

        elif 'open bluestack' in query:

            appli = r"C:\ProgramData\BlueStacks\Client\Bluestacks.exe"

            os.startfile(appli)

        elif 'news' in query:

            try:

                jsonObj = urlopen()

                data = json.load(jsonObj)

                i = 1

                speak('here are some top news from the times of india')

                print(+ 'n')

                for item in data['articles']:

                    print(str(i) + '. ' + item['title'] + 'n')

                    print(item['description'] + 'n')

                    speak(str(i) + '. ' + item['title'] + 'n')

                    i += 1

            except Exception as e:

                print(str(e))

        elif 'lock window' in query:

                speak("locking the device")

                ctypes.windll.user32.LockWorkStation()

        elif 'shutdown system' in query:

                speak("Hold On a Sec ! Your system is on its way to shut down")

                subprocess.call('shutdown / p /f')

        elif 'empty recycle bin' in query:

            winshell.recycle_bin().empty(confirm = False, show_progress = False, sound = True)

            speak("Recycle Bin Recycled")

        elif "don't listen" in query or "stop listening" in query:

            speak("for how much time you want to stop jarvis from listening commands")

            a = int(takeCommand())

            time.sleep(a)

            print(a)

        elif "where is" in query:

            query = query.replace("where is", "")

            location = query

            speak("User asked to Locate")

            speak(location)

        elif "camera" in query or "take a photo" in query:

            ec.capture(0, "Jarvis Camera ", "img.jpg")

        elif "restart" in query:

            subprocess.call(["shutdown", "/r"])

        elif "hibernate" in query or "sleep" in query:

            speak("Hibernating")

            subprocess.call("shutdown / h")

        elif "log off" in query or "sign out" in query:

            speak("Make sure all the application are closed before sign-out")

            time.sleep(5)

            subprocess.call(["shutdown", "/l"])

        elif "write a note" in query:

            speak("What should i write, sir")

            note = takeCommand()

            file = open('jarvis.txt', 'w')

            speak("Sir, Should i include date and time")

            snfm = takeCommand()

            if 'yes' in snfm or 'sure' in snfm:

                strTime = datetime.datetime.now().strftime("% H:% M:% S")

                file.write(strTime)

                file.write(" :- ")

                file.write(note)

            else:

                file.write(note)

        elif "show note" in query:

            speak("Showing Notes")

            file = open("jarvis.txt", "r")

            print(file.read())

            speak(file.read(6))

        elif "update assistant" in query:

            speak("After downloading file please replace this file with the downloaded one")

            url = '# url after uploading file'

            r = requests.get(url, stream = True)

            with open("Voice.py", "wb") as Pypdf:

                total_length = int(r.headers.get('content-length'))

                for ch in progress.bar(r.iter_content(chunk_size = 2391975),

                                       expected_size =(total_length / 1024) + 1):

                    if ch:

                      Pypdf.write(ch)

        elif "jarvis" in query:

            wishMe()

            speak("Jarvis 1 point o in your service Mister")

            speak(assname)

        elif "weather" in query:

            api_key = "Api key"

            speak(" City name ")

            print("City name : ")

            city_name = takeCommand()

            complete_url = base_url + "appid =" + api_key + "&q =" + city_name

            response = requests.get(complete_url)

            x = response.json()

            if x["code"] != "404":

                y = x["main"]

                current_temperature = y["temp"]

                current_pressure = y["pressure"]

                current_humidiy = y["humidity"]

                z = x["weather"]

                weather_description = z[0]["description"]

                print(" Temperature (in kelvin unit) = " +str(current_temperature)+"n atmospheric pressure (in hPa unit) ="+str(current_pressure) +"n humidity (in percentage) = " +str(current_humidiy) +"n description = " +str(weather_description))

            else:

                speak(" City Not Found ")

        elif "send message " in query:

                account_sid = 'Account Sid key'

                auth_token = 'Auth token'

                client = Client(account_sid, auth_token)

                message = client.messages

                                .create(

                                    body = takeCommand(),

                                    from_='Sender No',

                                    to ='Receiver No'

                                )

                print(message.sid)

        elif "wikipedia" in query:

            webbrowser.open("wikipedia.com")

        elif "Good Morning" in query:

            speak("A warm" +query)

            speak("How are you Mister")

            speak(assname)

        elif "will you be my gf" in query or "will you be my bf" in query:  

            speak("I'm not sure about, may be you should give me some time")

        elif "how are you" in query:

            speak("I'm fine, glad you me that")

        elif "i love you" in query:

            speak("It's hard to understand")

        elif "what is" in query or "who is" in query:

            client = wolframalpha.Client("API_ID")

            res = client.query(query)

            try:

                print (next(res.results).text)

                speak (next(res.results).text)

            except StopIteration:

                print ("No results")

Понравилась статья? Поделить с друзьями:
  • Как написать годный фанфик
  • Как написать год на английском словами
  • Как написать гневное письмо поставщику
  • Как написать гмаил на компьютер
  • Как написать глухонемому