2022-05-16 08:48:01 +00:00
# Модуль машины состояний (конечный автомат)
2022-05-21 17:06:44 +00:00
import speaker # Для воспроизведения
import listener # Для распознавание речи
2022-05-16 08:48:01 +00:00
import datetime # Для времени
2022-05-16 09:33:50 +00:00
from pyowm import OWM # Использование OpenWeatherMap для получения данных о погоде (pip install pyowm)
import random
2022-05-16 10:09:04 +00:00
import traceback # вывод traceback без остановки работы программы при отлове исключений
2022-05-16 08:48:01 +00:00
2022-05-21 17:06:44 +00:00
2022-05-16 08:48:01 +00:00
machine = None # Конечный автомат
current_state = None # Текущее состояние
weather_api_key = None # Ключ для OpenWeatherMap
2022-05-16 09:44:51 +00:00
myName = None # Имя ассистента
2022-05-16 08:48:01 +00:00
def init ( assistant_name ) :
""" Инициализирует конечный автомат """
global machine
global current_state
global weather_api_key
2022-05-16 09:44:51 +00:00
global myName
2022-05-21 17:06:44 +00:00
listener . init_listener ( ) # Инициализация распозавания
2022-05-16 09:44:51 +00:00
myName = assistant_name
2022-05-16 08:48:01 +00:00
with open ( " weatherApiKey.txt " , " r " ) as key :
weather_api_key = key . read ( )
current_state = " Начало "
machine = {
" Начало " : {
assistant_name . lower ( ) : switchToListen
} ,
" Слушаю задание " : {
" время " : switchToTime ,
2022-05-16 09:33:50 +00:00
" погода " : switchToWeather ,
" привет " : switchToHello ,
" здравствуй " : switchToHello ,
" доброе утро " : switchToHello ,
" добрый день " : switchToHello ,
" добрый вечер " : switchToHello ,
" доброй ночи " : switchToHello ,
" пока " : switchToBye ,
2022-05-16 09:44:51 +00:00
" до встречи " : switchToBye ,
" перезапуск " : switchToReboot ,
" завершение работы " : turnOff
} ,
2022-05-16 08:48:01 +00:00
}
2022-05-16 09:44:51 +00:00
switchToHello ( )
speaker . speak ( f " Ассистент { myName } начинает работу " )
2022-05-16 08:48:01 +00:00
def work ( ) :
""" Обрабатывает конечный автомат """
global current_state
while ( True ) :
2022-05-21 17:06:44 +00:00
#word = input().lower() # Пока считаем с клавиатуры предложение
word = listener . recognize ( ) # Слушаем и распознаем
2022-05-16 08:48:01 +00:00
# Если ассистент знает такое слово для перехода
if ( word in machine [ current_state ] . keys ( ) ) :
# Выполняем действия и переход в новое состояние
current_state = machine [ current_state ] [ word ] ( )
2022-05-16 10:05:29 +00:00
elif ( current_state != ' Начало ' ) :
2022-05-16 08:48:01 +00:00
# иначе переспросим
speaker . speak ( " Я не понял, пожалуйста повторите " )
2022-05-21 17:06:44 +00:00
print ( " Сейчас автомат в: " + current_state + " . Я услышал: " + word )
2022-05-16 08:48:01 +00:00
# Переход на "Слушаю задание"
def switchToListen ( ) :
speaker . speak ( " Слушаю " )
return " Слушаю задание "
# Переход на "Говорю время" и возвращаюсь в "Начало"
def switchToTime ( ) :
now = datetime . datetime . now ( )
2022-05-21 20:35:29 +00:00
time = f ' Сейчас { now . hour } '
if now . hour == 0 or 5 < = now . hour < = 20 :
time + = ' часов '
if now . hour == 1 or now . hour == 21 :
time + = ' час '
if 2 < = now . hour % 20 < = 4 :
time + = ' часАА ' # тянем слог
time + = str ( now . minute )
if now . minute % 10 == 1 and now . minute != 11 :
time + = ' минута '
elif 5 < = now . minute < = 20 or 25 < = now . minute < = 30 or 35 < = now . minute < = 40 or 45 < = now . minute < = 50 or 55 < = now . minute :
time + = ' минут '
else :
time + = ' минуты '
speaker . speak ( time )
2022-05-16 08:48:01 +00:00
return " Начало "
2022-05-21 19:45:03 +00:00
def _precipitation_today_message ( precipitations : list ) :
# Собираем время для проверки что осадки в будущем сегодня
today = datetime . datetime . now ( ) . replace ( hour = 23 , minute = 59 , second = 59 ) # Зададим конец дня
for precipitation in precipitations :
# Время осадков
precipitation_time = datetime . datetime . fromisoformat ( precipitation . reference_time ( ' iso ' ) ) . replace ( tzinfo = None ) # во избежания ошибок сравнения относительного и абсолютного времени
# Если осадки в будущем сегодня
if datetime . datetime . now ( ) < = precipitation_time < = today :
return f ' Обещают { precipitation . detailed_status } в { precipitation_time . hour } часов ' # Достаточно сказать о б одних осадках
return ' ' # Если осадков подходящих не нашлось - пустая строка
2022-05-16 08:48:01 +00:00
# Переход на "Вопрос локации погоды"
def switchToWeather ( ) :
2022-05-16 10:02:59 +00:00
location = " Murino,RU "
2022-05-16 08:48:01 +00:00
try :
open_weather_map = OWM ( weather_api_key )
2022-05-21 19:45:03 +00:00
open_weather_map . config [ ' language ' ] = ' ru ' # Язык результатов
2022-05-16 08:48:01 +00:00
# запрос данных о текущем состоянии погоды
2022-05-21 19:45:03 +00:00
now = open_weather_map . weather_manager ( ) . weather_at_place ( location )
forecast = open_weather_map . weather_manager ( ) . forecast_at_place ( location , ' 3h ' ) # 3h вернет недельный, так как daily не работает
2022-05-16 08:48:01 +00:00
except :
speaker . speak ( " Извините. Ошибка запроса к серверу погоды " )
traceback . print_exc ( ) # Вывод трейсбека для отладки
return " Начало "
# разбивание данных на части для удобства работы с ними
2022-05-21 19:45:03 +00:00
status = now . weather . detailed_status
temperature = int ( now . weather . temperature ( ' celsius ' ) [ " temp " ] )
# Начинаем собирать строку с погодой
weather = f " Сейчас { status } { temperature } градусов. "
# Если в прогнозе есть дождь
if forecast . will_have_rain ( ) :
weather + = _precipitation_today_message ( forecast . when_rain ( ) )
# Если в прогнозе есть снег
if forecast . will_have_snow ( ) :
weather + = _precipitation_today_message ( forecast . when_rain ( ) )
speaker . speak ( weather )
2022-05-16 09:33:50 +00:00
return " Начало "
# Переход на приветствие и на "Начало"
def switchToHello ( ) :
helloWords = [ " Привет " , " Здравствуй " , " Доброго времени суток " ]
random_index = random . randint ( 0 , len ( helloWords ) )
# Если выпадает больше нуля - берем готовую
if ( random_index > 0 ) :
hi = helloWords [ random_index - 1 ]
else :
# Иначе генерируем время суток
now = datetime . datetime . now ( )
if ( now . hour < 5 or now . hour > 21 ) :
hi = " Доброй ночи "
elif ( now . hour < 12 ) :
hi = " Доброе утро "
elif ( now . hour < 16 ) :
hi = " Добрый день "
else :
hi = " Добрый вечер "
speaker . speak ( hi )
return " Начало "
# Переход на приветствие и на "Начало"
def switchToBye ( ) :
helloWords = [ " Пока " , " Удачи " , " Я всегда тут, буду ждать " ]
speaker . speak ( random . choice ( helloWords ) )
2022-05-16 09:44:51 +00:00
return " Начало "
# Переход на запрос модуля для перезагрузки и на "Начало":
def switchToReboot ( ) :
init ( myName )
return " Начало "
# Завершение работы
def turnOff ( ) :
raise SystemExit