1
0
mirror of https://github.com/MarkParker5/STARK.git synced 2025-02-12 11:46:14 +02:00
STARK/tests/conftest.py
2023-09-20 10:00:46 +02:00

173 lines
6.5 KiB
Python

from typing import AsyncGenerator
import time
import contextlib
import pytest
import asyncer
import anyio
from stark.general.dependencies import DependencyManager
from stark.core import (
CommandsManager,
CommandsContext,
CommandsContextDelegate,
Response,
ResponseHandler,
AsyncResponseHandler
)
from stark.core.types import Word
from stark.interfaces.protocols import SpeechRecognizerDelegate
from stark.voice_assistant import VoiceAssistant
class CommandsContextDelegateMock(CommandsContextDelegate):
responses: list[Response]
def __init__(self):
self.responses = []
async def commands_context_did_receive_response(self, response: Response):
self.responses.append(response)
async def remove_response(self, response: Response):
self.responses.remove(response)
class SpeechRecognizerMock:
is_recognizing: bool = False
delegate: SpeechRecognizerDelegate | None = None
async def start_listening(self): pass
def stop_listening(self): pass
class SpeechSynthesizerResultMock:
async def play(self): pass
def __init__(self, text: str):
self.text = text
class SpeechSynthesizerMock:
def __init__(self):
self.results = []
async def synthesize(self, text: str) -> SpeechSynthesizerResultMock:
result = SpeechSynthesizerResultMock(text)
self.results.append(result)
return result
@pytest.fixture
async def commands_context_flow():
@contextlib.asynccontextmanager
async def _commands_context_flow() -> AsyncGenerator[tuple[CommandsManager, CommandsContext, CommandsContextDelegateMock], None]:
async with asyncer.create_task_group() as main_task_group:
dependencies = DependencyManager()
manager = CommandsManager()
context = CommandsContext(main_task_group, manager, dependencies)
context_delegate = CommandsContextDelegateMock()
context.delegate = context_delegate
assert len(context_delegate.responses) == 0
assert len(context._context_queue) == 1
main_task_group.soonify(context.handle_responses)()
yield (manager, context, context_delegate)
context.stop()
return _commands_context_flow
@pytest.fixture
async def commands_context_flow_filled(commands_context_flow):
@contextlib.asynccontextmanager
async def _commands_context_flow_filled() -> AsyncGenerator[tuple[CommandsContext, CommandsContextDelegateMock], None]:
async with commands_context_flow() as (manager, context, context_delegate):
@manager.new('test')
def test():
text = voice = 'test'
return Response(text = text, voice = voice)
@manager.new('lorem * dolor')
def lorem():
return Response(text = 'Lorem!', voice = 'Lorem!')
@manager.new('hello', hidden = True)
def hello_context(**params):
voice = text = f'Hi, {params["name"]}!'
return Response(text = text, voice = voice)
@manager.new('bye', hidden = True)
def bye_context(name: Word, handler: ResponseHandler):
handler.pop_context()
return Response(
text = f'Bye, {name}!'
)
@manager.new('hello $name:Word')
def hello(name: Word):
text = voice = f'Hello, {name}!'
return Response(
text = text,
voice = voice,
commands = [hello_context, bye_context],
parameters = {'name': name}
)
@manager.new('repeat')
def repeat():
return Response.repeat_last
# background commands
@manager.new('background min')
async def background(handler: AsyncResponseHandler):
text = voice = 'Starting background task'
await handler.respond(Response(text = text, voice = voice))
await anyio.sleep(1)
text = voice = 'Finished background task'
return Response(text = text, voice = voice)
@manager.new('background needs input')
async def background_needs_input(handler: AsyncResponseHandler):
await anyio.sleep(1)
for text in ['First response', 'Second response', 'Third response']:
await handler.respond(Response(text = text, voice = text))
text = 'Needs input'
await handler.respond(Response(text = text, voice = text, needs_user_input = True))
for text in ['Fourth response', 'Fifth response', 'Sixth response']:
await handler.respond(Response(text = text, voice = text))
text = voice = 'Finished long background task'
return Response(text = text, voice = voice)
@manager.new('background with context')
async def background_multiple_contexts(handler: AsyncResponseHandler):
await anyio.sleep(1)
text = voice = 'Finished long background task'
return Response(text = text, voice = voice, commands = [hello_context, bye_context], parameters = {'name': 'John'})
@manager.new('background remove response')
async def background_remove_response(handler: AsyncResponseHandler):
response = Response(text = 'Deleted response', voice = 'Deleted response')
await handler.respond(response)
await anyio.sleep(1)
await handler.unrespond(response)
return None
yield (context, context_delegate)
return _commands_context_flow_filled
@pytest.fixture
async def voice_assistant(commands_context_flow_filled):
@contextlib.asynccontextmanager
async def _voice_assistant() -> AsyncGenerator[VoiceAssistant, None]:
async with commands_context_flow_filled() as (context, context_delegate):
voice_assistant = VoiceAssistant(
speech_recognizer = SpeechRecognizerMock(),
speech_synthesizer = SpeechSynthesizerMock(),
commands_context = context
)
yield voice_assistant
return _voice_assistant