You've already forked Irene-Voice-Assistant
mirror of
https://github.com/janvarev/Irene-Voice-Assistant.git
synced 2025-11-26 22:50:58 +02:00
v4.0
- поддержки работы с контекстом (см. справку) - демо-игра работы с контекстом Больше-меньше и Больше-меньше альтернативная (два стиля) - базовые реализации используют работы с контекстом - runva_webapi.py - теперь вызовы core._update_timers делаются через периодичпеские вызовы HTTP, и через таймер. Webapi стало значительно устойчивей - справка содержит информацию о контексте
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
**plugin_yandex_rasp.py** - расписание ближайших электричек через Яндекс.Расписания. Пример: "электричка, электрички".
|
||||
Требует установки в конфиге бесплатного API-ключа для личных нужд (до 500 запросов в сутки) с https://yandex.ru/dev/rasp/raspapi/ , а также станций отправления и назначения
|
||||
|
||||
**plugin_gamemoreless.py** - игра Больше-меньше. Команда "игра больше меньше". Является примером работы с контекстом в движке Ирины.
|
||||
|
||||
---
|
||||
|
||||
**plugin_tts_pyttsx.py** - (оффлайн) позволяет делать TTS (Text-To-Speech, озвучку текста) через pyttsx движок. Используется по умолчанию.
|
||||
@@ -61,6 +63,9 @@
|
||||
|
||||
**plugin_youtubesearch.py** - поиск на Ютубе. Пример: "ютуб остров сокровищ". Открывает страницу в браузере с поиском. (Inspired by @EnjiRouz)
|
||||
|
||||
**plugin_gamemoreless_alt.py** - альтернативная реализация игры Больше-меньше. Команда "игра меньше больше".
|
||||
Является примером работы с контекстом альтернативным способом (**рекомендуется**) в движке Ирины.
|
||||
|
||||
**plugin_tts_silero.py** - (оффлайн) TTS через Silero. При первом запуске требует онлайна, чтобы скачать файл с нейросетью.
|
||||
Требует pytorch 1.9+. На мой взгляд, работает немного медленно + не озвучивает числа, требуя их перевода в числительные + шипит. Тем не менее, очень крут!
|
||||
Голос задается в конфиге.
|
||||
|
||||
58
README.md
58
README.md
@@ -44,6 +44,64 @@
|
||||
|
||||
Полная информация: [PLUGINS.md](/PLUGINS.md)
|
||||
|
||||
### Поддержка контекста (с версии 4.0)
|
||||
|
||||
Обычно запуск любой команды требует префикса имени ассистента
|
||||
(напр, "Ирина, погода"). Но иногда это избыточно - например, если мы пишем игру, и команды идут непрерывно.
|
||||
|
||||
С версии 4.0 поддерживается установление **контекста**. В контексте
|
||||
движок:
|
||||
* принимает фразы без префикса Ирина (имени ассистента)
|
||||
* сразу передает их в функцию обработки контекста
|
||||
|
||||
**Как работает**
|
||||
|
||||
При вызове функции обработки можно вызвать функцию
|
||||
```
|
||||
core.context_set(new_context)
|
||||
```
|
||||
|
||||
Контекст будет держаться 10 секунд, потом будет сброшен
|
||||
(нужно, чтобы Ирина не зависала в состоянии, если пользователь ушел)
|
||||
|
||||
Пока контекст установлен, любой непустой вход (фраза) будет сразу
|
||||
подана на вход функции контекста, после чего **контекст будет сброшен!**
|
||||
|
||||
Таким образом, если вы хотите продолжать взаимодействовать с контекстом,
|
||||
нужно после каждого вызова функции его устанавливать повторно.
|
||||
|
||||
**Пример**
|
||||
|
||||
Для примера доступна игра "Больше-меньше" (плагин plugins/plugin_gamemoreless.py).
|
||||
Запустите её с помощью команды "ирина игра больше меньше"
|
||||
|
||||
Также доступен второй тип задания контекста в альтернативной реализации игры
|
||||
plugins_inactive/plugin_gamemoreless_alt.py.
|
||||
**Альтернативный вариант рекомендуется больше, чем основной**
|
||||
|
||||
**Типы контекста**
|
||||
|
||||
Контекст может задаваться двумя способами:
|
||||
1. Как функция, принимающая текстовый ввод (пример в игре больше меньше plugins/plugin_gamemoreless.py)
|
||||
|
||||
2. Как словарь команд внутри контекста - такой же, как при задании команд Ирины в манифесте плагина. В этом
|
||||
случае движок будет пытаться распознать команду внутри контекста,
|
||||
и в случае нераспознавания контекст будет переустановлен.
|
||||
|
||||
Пример диалога во втором варианте:
|
||||
```
|
||||
В: ирина игра больше меньше
|
||||
О: скажи правила или начать
|
||||
В: тест
|
||||
О: не поняла (контекст сохранился, по-прежнему можно сказать правила)
|
||||
```
|
||||
|
||||
Пример реализации игры Больше-меньше в альтернативном варианте есть в файле
|
||||
plugins_inactive/plugin_gamemoreless_alt.py (нужно перенести в plugins_active,
|
||||
а затем запустить командой "игра меньше больше")
|
||||
|
||||
|
||||
|
||||
### Сторонние плагины
|
||||
|
||||
Если вы хотите узнать:
|
||||
|
||||
@@ -21,6 +21,7 @@ def start(core:VACore):
|
||||
"logPolicy": "cmd", # all | cmd | none
|
||||
|
||||
"replyNoCommandFound": "Извини, я не поняла",
|
||||
"replyNoCommandFoundInContext": "Не поняла...",
|
||||
"replyOnlineRequired": "Для этой команды необходим онлайн",
|
||||
|
||||
"tempDir": "temp",
|
||||
|
||||
84
plugins/plugin_gamemoreless.py
Normal file
84
plugins/plugin_gamemoreless.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# Игра больше меньше
|
||||
# author: Vladislav Janvarev
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from vacore import VACore
|
||||
import random
|
||||
|
||||
# функция на старте
|
||||
def start(core:VACore):
|
||||
manifest = { # возвращаем настройки плагина - словарь
|
||||
"name": "Игра больше меньше", # имя
|
||||
"version": "1.0", # версия
|
||||
"require_online": False, # требует ли онлайн?
|
||||
|
||||
"commands": { # набор скиллов. Фразы скилла разделены | . Если найдены - вызывается функция
|
||||
"игра больше меньше": play_game_start,
|
||||
}
|
||||
}
|
||||
return manifest
|
||||
|
||||
questNumber = -1
|
||||
tries = 0
|
||||
|
||||
def play_game_start(core:VACore, phrase: str): # в phrase находится остаток фразы после названия скилла,
|
||||
# если юзер сказал больше
|
||||
# в этом плагине не используется
|
||||
core.play_voice_assistant_speech("Скажи правила или начать")
|
||||
core.context_set(play_1)
|
||||
|
||||
def play_1(core:VACore, phrase: str):
|
||||
if phrase == "правила":
|
||||
core.play_voice_assistant_speech("Правила игры. Я загадываю число от одного до тридцати. "
|
||||
"Ты называешь число, а я говорю, загаданное число больше названного, или меньше. "
|
||||
"Твоя задача - отгадать число за пять попыток. Скажи начать для начала игры.")
|
||||
core.context_set(play_1)
|
||||
return
|
||||
if phrase == "начать" or phrase == "скачать" or phrase == "повторить":
|
||||
global questNumber, tries
|
||||
questNumber = random.randint(1,30)
|
||||
#print(questNumber)
|
||||
tries = 0
|
||||
core.play_voice_assistant_speech("Число от одного до тридцати загадано. Начинаем!")
|
||||
#play_game_start(core,"")
|
||||
core.context_set(play_2)
|
||||
return
|
||||
|
||||
if phrase == "отмена":
|
||||
core.say("Поняла, играть не будем")
|
||||
return
|
||||
|
||||
core.play_voice_assistant_speech("Не поняла...")
|
||||
core.context_set(play_1)
|
||||
|
||||
def play_2(core:VACore, phrase: str):
|
||||
from utils.num_to_text_ru import num2text
|
||||
for i in range(1,31):
|
||||
if phrase == num2text(i):
|
||||
global tries
|
||||
tries += 1
|
||||
if i == questNumber:
|
||||
core.say("Да, ты угадал. Поздравляю с победой! Скажи повторить, если хочешь сыграть еще раз.")
|
||||
core.context_set(play_1)
|
||||
return
|
||||
else:
|
||||
txtsay = ""
|
||||
if i < questNumber:
|
||||
txtsay += "Больше. "
|
||||
else:
|
||||
txtsay += "Меньше. "
|
||||
|
||||
if tries >= 5:
|
||||
txtsay += "Пять попыток прошло, к сожалению, ты проиграл. А я загадала число "+num2text(questNumber)
|
||||
txtsay += ". Скажи повторить, если хочешь сыграть еще раз."
|
||||
core.say(txtsay)
|
||||
core.context_set(play_1)
|
||||
return
|
||||
else:
|
||||
core.say(txtsay)
|
||||
core.context_set(play_2)
|
||||
return
|
||||
|
||||
core.play_voice_assistant_speech("Не поняла число, скажи еще раз!")
|
||||
core.context_set(play_2)
|
||||
91
plugins_inactive/plugin_gamemoreless_alt.py
Normal file
91
plugins_inactive/plugin_gamemoreless_alt.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# Игра больше меньше (альтернативная реализация на меню)
|
||||
# author: Vladislav Janvarev
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from vacore import VACore
|
||||
import random
|
||||
|
||||
# функция на старте
|
||||
def start(core:VACore):
|
||||
manifest = { # возвращаем настройки плагина - словарь
|
||||
"name": "Игра больше меньше (альтернативная реализация)", # имя
|
||||
"version": "1.0", # версия
|
||||
"require_online": False, # требует ли онлайн?
|
||||
|
||||
"commands": { # набор скиллов. Фразы скилла разделены | . Если найдены - вызывается функция
|
||||
"игра меньше больше": play_game_start,
|
||||
}
|
||||
}
|
||||
return manifest
|
||||
|
||||
questNumber = -1
|
||||
tries = 0
|
||||
|
||||
|
||||
|
||||
def play_game_start(core:VACore, phrase: str): # в phrase находится остаток фразы после названия скилла,
|
||||
# если юзер сказал больше
|
||||
# в этом плагине не используется
|
||||
core.play_voice_assistant_speech("Скажи правила или начать")
|
||||
core.context_set(menu_main) # меню - набор фраз и правил, в конце файла
|
||||
|
||||
def play_cancel(core:VACore, phrase: str):
|
||||
core.say("Поняла, играть не будем")
|
||||
return
|
||||
|
||||
def play_rules(core:VACore, phrase: str):
|
||||
core.play_voice_assistant_speech("Правила игры. Я загадываю число от одного до тридцати. "
|
||||
"Ты называешь число, а я говорю, загаданное число больше названного, или меньше. "
|
||||
"Твоя задача - отгадать число за пять попыток. Скажи начать для начала игры.")
|
||||
core.context_set(menu_main)
|
||||
|
||||
|
||||
def play_start(core:VACore, phrase: str):
|
||||
global questNumber, tries
|
||||
questNumber = random.randint(1,30)
|
||||
#print(questNumber)
|
||||
tries = 0
|
||||
core.play_voice_assistant_speech("Число от одного до тридцати загадано. Начинаем!")
|
||||
core.context_set(menu_in_game)
|
||||
return
|
||||
|
||||
def play_game(core:VACore, phrase: str, i: int):
|
||||
if phrase != "":
|
||||
# что-то не распозналось или было добавлено. Просим повторить еще раз
|
||||
core.say("Извини, не поняла число")
|
||||
core.context_set(menu_in_game)
|
||||
return
|
||||
|
||||
global tries
|
||||
tries += 1
|
||||
if i == questNumber:
|
||||
core.say("Да, ты угадал. Поздравляю с победой! Скажи повторить, если хочешь сыграть еще раз.")
|
||||
core.context_set(menu_main)
|
||||
return
|
||||
else:
|
||||
txtsay = ""
|
||||
if i < questNumber:
|
||||
txtsay += "Больше. "
|
||||
else:
|
||||
txtsay += "Меньше. "
|
||||
|
||||
if tries >= 5:
|
||||
txtsay += "Пять попыток прошло, к сожалению, ты проиграл. А я загадала число "+num2text(questNumber)
|
||||
txtsay += ". Скажи повторить, если хочешь сыграть еще раз."
|
||||
core.say(txtsay)
|
||||
core.context_set(menu_main)
|
||||
return
|
||||
else:
|
||||
core.say(txtsay)
|
||||
core.context_set(menu_in_game)
|
||||
return
|
||||
|
||||
|
||||
# game menus
|
||||
menu_main = {"правила":play_rules,"начать|скачать|повторить":play_start,"отмена":play_cancel}
|
||||
|
||||
menu_in_game = {}
|
||||
from utils.num_to_text_ru import num2text
|
||||
for i in range(1,31):
|
||||
menu_in_game[num2text(i)] = (play_game, i)
|
||||
@@ -62,23 +62,7 @@ if __name__ == "__main__":
|
||||
voice_input_str = record_and_recognize_audio()
|
||||
|
||||
if voice_input_str != "":
|
||||
#print("Input: ",voice_input)
|
||||
if core.logPolicy == "all":
|
||||
print("Input: ",voice_input_str)
|
||||
core.run_input_str(voice_input_str)
|
||||
|
||||
try:
|
||||
voice_input = voice_input_str.split(" ")
|
||||
#callname = voice_input[0]
|
||||
for ind in range(len(voice_input)):
|
||||
callname = voice_input[ind]
|
||||
if callname in core.voiceAssNames: # найдено имя ассистента
|
||||
if core.logPolicy == "cmd":
|
||||
print("Input (cmd): ",voice_input_str)
|
||||
|
||||
command_options = " ".join([str(input_part) for input_part in voice_input[(ind+1):len(voice_input)]])
|
||||
core.execute_next(command_options, None)
|
||||
break
|
||||
except Exception as err:
|
||||
print(traceback.format_exc())
|
||||
|
||||
core._update_timers()
|
||||
@@ -11,6 +11,11 @@ from vacore import VACore
|
||||
|
||||
mic_blocked = False
|
||||
|
||||
def block_mic():
|
||||
global mic_blocked
|
||||
#print("Blocking microphone...")
|
||||
mic_blocked = True
|
||||
|
||||
# ------------------- vosk ------------------
|
||||
if __name__ == "__main__":
|
||||
q = queue.Queue()
|
||||
@@ -109,28 +114,11 @@ if __name__ == "__main__":
|
||||
|
||||
|
||||
if voice_input_str != "":
|
||||
#print("Input: ",voice_input)
|
||||
if core.logPolicy == "all":
|
||||
print("Input: ",voice_input_str)
|
||||
|
||||
try:
|
||||
voice_input = voice_input_str.split(" ")
|
||||
#callname = voice_input[0]
|
||||
for ind in range(len(voice_input)):
|
||||
callname = voice_input[ind]
|
||||
if callname in core.voiceAssNames: # найдено имя ассистента
|
||||
if core.logPolicy == "cmd":
|
||||
print("Input (cmd): ",voice_input_str)
|
||||
|
||||
mic_blocked = True
|
||||
command_options = " ".join([str(input_part) for input_part in voice_input[(ind+1):len(voice_input)]])
|
||||
core.execute_next(command_options, None)
|
||||
break
|
||||
except Exception as err:
|
||||
print(traceback.format_exc())
|
||||
core.run_input_str(voice_input_str,block_mic)
|
||||
|
||||
|
||||
mic_blocked = False
|
||||
#print("UNBlocking microphone...")
|
||||
else:
|
||||
#print("2",rec.PartialResult())
|
||||
pass
|
||||
@@ -144,4 +132,6 @@ if __name__ == "__main__":
|
||||
print('\nDone')
|
||||
parser.exit(0)
|
||||
except Exception as e:
|
||||
parser.exit(type(e).__name__ + ': ' + str(e))
|
||||
parser.exit(type(e).__name__ + ': ' + str(e))
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ def runCmd(cmd:str,returnFormat:str):
|
||||
core.remoteTTS = returnFormat
|
||||
core.remoteTTSResult = ""
|
||||
core.lastSay = ""
|
||||
core.execute_next(cmd,None)
|
||||
core.execute_next(cmd,core.context)
|
||||
core.remoteTTS = tmpformat
|
||||
|
||||
app = FastAPI()
|
||||
@@ -63,45 +63,40 @@ async def sendSimpleTxtCmd(cmd:str,returnFormat:str = "none"):
|
||||
# Пример: ирина погода, раз два
|
||||
@app.get("/sendRawTxt")
|
||||
async def sendRawTxt(rawtxt:str,returnFormat:str = "none"):
|
||||
voice_input = rawtxt.split(" ")
|
||||
|
||||
isFound = False
|
||||
for ind in range(len(voice_input)):
|
||||
callname = voice_input[ind]
|
||||
if callname in core.voiceAssNames: # найдено имя ассистента
|
||||
isFound = True
|
||||
if core.logPolicy == "cmd":
|
||||
print("Input (cmd): ",rawtxt)
|
||||
|
||||
command_options = " ".join([str(input_part) for input_part in voice_input[(ind+1):len(voice_input)]])
|
||||
runCmd(command_options, returnFormat)
|
||||
break
|
||||
tmpformat = core.remoteTTS
|
||||
core.remoteTTS = returnFormat
|
||||
core.remoteTTSResult = ""
|
||||
core.lastSay = ""
|
||||
isFound = core.run_input_str(rawtxt)
|
||||
core.remoteTTS = tmpformat
|
||||
|
||||
if isFound:
|
||||
return core.remoteTTSResult
|
||||
else:
|
||||
return "NO_VA_NAME"
|
||||
|
||||
# Запускает внутреннюю процедуру проверки таймеров. Должна запускаться периодически
|
||||
@app.get("/updTimers")
|
||||
async def updTimers():
|
||||
#core.say("аа")
|
||||
#print("upd timers")
|
||||
core._update_timers()
|
||||
return ""
|
||||
|
||||
# simple threading for timer
|
||||
from threading import Thread, Event
|
||||
|
||||
class MyThread(Thread):
|
||||
def __init__(self, event):
|
||||
Thread.__init__(self)
|
||||
self.stopped = event
|
||||
|
||||
def run(self):
|
||||
while not self.stopped.wait(0.5):
|
||||
core._update_timers()
|
||||
|
||||
if __name__ != "__main__": # must run only in web
|
||||
stopFlag = Event()
|
||||
thread = MyThread(stopFlag)
|
||||
thread.start()
|
||||
# this will stop the timer
|
||||
#stopFlag.set()
|
||||
def core_update_timers_http(runReq=True):
|
||||
from threading import Timer
|
||||
if runReq:
|
||||
try:
|
||||
import requests
|
||||
reqstr = "http://{0}:{1}/updTimers".format(webapi_options["host"],webapi_options["port"])
|
||||
#print(reqstr)
|
||||
r = requests.get(reqstr)
|
||||
except Exception:
|
||||
pass
|
||||
t = Timer(2, core_update_timers_http)
|
||||
t.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
core_update_timers_http(False)
|
||||
uvicorn.run("runva_webapi:app", host=webapi_options["host"], port=webapi_options["port"],
|
||||
log_level=webapi_options["log_level"])
|
||||
119
vacore.py
119
vacore.py
@@ -2,13 +2,16 @@ import os
|
||||
import traceback
|
||||
|
||||
import time
|
||||
from threading import Timer
|
||||
|
||||
import sounddevice as sound_device
|
||||
import soundfile as sound_file
|
||||
|
||||
from jaa import JaaCore
|
||||
|
||||
version = "3.3"
|
||||
version = "4.0"
|
||||
|
||||
# main VACore class
|
||||
|
||||
class VACore(JaaCore):
|
||||
def __init__(self):
|
||||
@@ -45,6 +48,10 @@ class VACore(JaaCore):
|
||||
self.remoteTTS = "none"
|
||||
self.remoteTTSResult = None
|
||||
|
||||
self.context = None
|
||||
self.contextTimer = None
|
||||
self.contextTimerLastDuration = 0
|
||||
|
||||
import mpcapi.core
|
||||
self.mpchc = mpcapi.core.MpcAPI()
|
||||
|
||||
@@ -150,10 +157,22 @@ class VACore(JaaCore):
|
||||
else:
|
||||
# it is function to call!
|
||||
#context(self,command)
|
||||
self.context_clear()
|
||||
self.call_ext_func_phrase(command,context)
|
||||
return
|
||||
|
||||
try:
|
||||
# первый проход - ищем полное совпадение
|
||||
for keyall in context.keys():
|
||||
keys = keyall.split("|")
|
||||
for key in keys:
|
||||
if command == key:
|
||||
rest_phrase = ""
|
||||
next_context = context[keyall]
|
||||
self.execute_next(rest_phrase,next_context)
|
||||
return
|
||||
|
||||
# второй проход - ищем частичное совпадение
|
||||
for keyall in context.keys():
|
||||
keys = keyall.split("|")
|
||||
for key in keys:
|
||||
@@ -161,21 +180,19 @@ class VACore(JaaCore):
|
||||
rest_phrase = command[(len(key)+1):]
|
||||
next_context = context[keyall]
|
||||
self.execute_next(rest_phrase,next_context)
|
||||
#print(next_context)
|
||||
#print(rest_phrase)
|
||||
|
||||
#if isinstance(next_context,dict):
|
||||
|
||||
|
||||
#commands[key](*args)
|
||||
#print
|
||||
return
|
||||
else:
|
||||
#print("Command not found", command_name)
|
||||
pass
|
||||
|
||||
|
||||
# if not founded
|
||||
self.play_voice_assistant_speech(self.plugin_options("core")["replyNoCommandFound"])
|
||||
if self.context == None:
|
||||
# no context
|
||||
self.say(self.plugin_options("core")["replyNoCommandFound"])
|
||||
else:
|
||||
# in context
|
||||
self.say(self.plugin_options("core")["replyNoCommandFoundInContext"])
|
||||
# restart timer for context
|
||||
if self.contextTimer != None:
|
||||
self.context_set(self.context,self.contextTimerLastDuration)
|
||||
except Exception as err:
|
||||
print(traceback.format_exc())
|
||||
|
||||
@@ -238,3 +255,79 @@ class VACore(JaaCore):
|
||||
# Wait until file is done playing
|
||||
status = sound_device.wait()
|
||||
|
||||
# -------- raw txt running -----------------
|
||||
def run_input_str(self,voice_input_str,func_before_run_cmd = None): # voice_input_str - строка распознавания голоса, разделенная пробелами
|
||||
# пример: "ирина таймер пять"
|
||||
if self.logPolicy == "all":
|
||||
if self.context == None:
|
||||
print("Input: ",voice_input_str)
|
||||
else:
|
||||
print("Input (in context): ",voice_input_str)
|
||||
|
||||
try:
|
||||
voice_input = voice_input_str.split(" ")
|
||||
#callname = voice_input[0]
|
||||
haveRun = False
|
||||
if self.context == None:
|
||||
for ind in range(len(voice_input)):
|
||||
callname = voice_input[ind]
|
||||
|
||||
if callname in self.voiceAssNames: # найдено имя ассистента
|
||||
if self.logPolicy == "cmd":
|
||||
print("Input (cmd): ",voice_input_str)
|
||||
|
||||
|
||||
command_options = " ".join([str(input_part) for input_part in voice_input[(ind+1):len(voice_input)]])
|
||||
|
||||
# running some cmd before run cmd
|
||||
if func_before_run_cmd != None:
|
||||
func_before_run_cmd()
|
||||
|
||||
|
||||
#context = self.context
|
||||
#self.context_clear()
|
||||
self.execute_next(command_options, None)
|
||||
haveRun = True
|
||||
break
|
||||
else:
|
||||
if self.logPolicy == "cmd":
|
||||
print("Input (cmd in context): ",voice_input_str)
|
||||
|
||||
# running some cmd before run cmd
|
||||
if func_before_run_cmd != None:
|
||||
func_before_run_cmd()
|
||||
|
||||
self.execute_next(voice_input_str, self.context)
|
||||
haveRun = True
|
||||
|
||||
except Exception as err:
|
||||
print(traceback.format_exc())
|
||||
|
||||
return haveRun
|
||||
|
||||
# ------------ context handling functions ----------------
|
||||
|
||||
def context_set(self,context,duration = None):
|
||||
if duration == None:
|
||||
duration = 10
|
||||
|
||||
self.context_clear()
|
||||
|
||||
self.context = context
|
||||
self.contextTimerLastDuration = duration
|
||||
self.contextTimer = Timer(duration,self._context_clear_timer)
|
||||
self.contextTimer.start()
|
||||
|
||||
#def _timer_context
|
||||
def _context_clear_timer(self):
|
||||
print("Context cleared after timeout")
|
||||
self.contextTimer = None
|
||||
self.context_clear()
|
||||
|
||||
def context_clear(self):
|
||||
self.context = None
|
||||
if self.contextTimer != None:
|
||||
self.contextTimer.cancel()
|
||||
self.contextTimer = None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user