Skip to content

Commit

Permalink
expose submit_active_interaction for non-skill plugins; add notificat…
Browse files Browse the repository at this point in the history
…ion api plugin
  • Loading branch information
AlexeyBond committed Jan 30, 2025
1 parent e194469 commit 9e7e3c1
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 26 deletions.
59 changes: 33 additions & 26 deletions irene/brain/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,32 @@ def meta(self) -> MetadataMapping:
return super().meta


class Brain(metaclass=ABCMeta):
class VAApiBase(ABC):
"""
API голосового ассистента, доступный вне обработчиков команд.
"""

@abstractmethod
def submit_active_interaction(
self,
interaction: 'VAActiveInteractionSource',
*,
related_message: Optional['InboundMessage'] = None,
):
"""
Начинает активное взаимодействие.
Args:
interaction:
related_message:
ранее полученное сообщение, связанное с взаимодействием.
Это сообщение будет доступно через метод ``get_message`` взаимодействиям, использующим ``VAApiExt``.
Если сообщение не передано явно, то реализация ``VAApi`` может попытаться обнаружить последнее
полученное сообщение и использовать его.
"""


class Brain(VAApiBase, metaclass=ABCMeta):
"""
API голосового ассистента, доступный плагинам, реализующим средства ввода/вывода (распознание/синтез речи, обмен
сообщениями через мессенджеры и т.д.).
Expand Down Expand Up @@ -176,7 +201,7 @@ def send_messages(
"""


class VAApi(metaclass=ABCMeta):
class VAApi(VAApiBase, ABC):
"""
API голосового ассистента, доступный плагинам, добавляющим дополнительные команды/скиллы.
"""
Expand Down Expand Up @@ -234,25 +259,6 @@ def play_audio(self, file_path: str, **kwargs):

ch.send_file(file_path, **kwargs)

@abstractmethod
def submit_active_interaction(
self,
interaction: 'VAActiveInteractionSource',
*,
related_message: Optional['InboundMessage'] = None,
):
"""
Начинает активное взаимодействие.
Args:
interaction:
related_message:
ранее полученное сообщение, связанное с взаимодействием.
Это сообщение будет доступно через метод ``get_message`` взаимодействиям, использующим ``VAApiExt``.
Если сообщение не передано явно, то реализация ``VAApi`` может попытаться обнаружить последнее
полученное сообщение и использовать его.
"""


class VAApiExt(VAApi, ABC):
"""
Expand Down Expand Up @@ -527,12 +533,13 @@ def handle_restore(self, va: VAApi) -> Optional['VAContext']:

T = TypeVar('T')

# VAContextSourcesDict = dict[str, 'VAContextSource'] # пока не поддерживается в mypy
VAContextSourcesDict = dict[str, Any]
VAContextSourcesDict = dict[str, 'VAContextSource']

# yield type, send type, return type
VAContextGenerator = Generator[Optional[Union[str,
Tuple[str, float]]], str, Optional[str]]
# yield type, send type, return type.
# yield type. Генератор может yield'ить фразу, которую нужно сказать (в виде строки) или tuple из фразы и таймаута
# send type. Генератор будет получать из yield произнесённый/введённый пользователем текст
# return type. Генератор может вернуть последнюю фразу, которую нужно произнести
VAContextGenerator = Generator[Optional[Union[str, Tuple[str, float]]], str, Optional[str]]

VAContextSource = Union[
VAContext,
Expand Down
13 changes: 13 additions & 0 deletions irene/brain/brain.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __init__(
self._outputs = CompositeOutputPool((predefined_outputs,))
self._api_provider = _VAApiProvider(
outputs=self._outputs, context_constructor=context_constructor)
self._context_constructor = context_constructor

self._context_manager = VAContextManager(
self._api_provider.get_api(),
Expand All @@ -102,6 +103,18 @@ def __init__(
self._context_manager, config['timeoutCheckInterval'])
self._ticker.start()

def submit_active_interaction(
self,
interaction: VAActiveInteractionSource, *,
related_message: Optional['InboundMessage'] = None
):
ai = construct_active_interaction(
interaction,
related_message=related_message,
construct_context=self._context_constructor,
)
self._context_manager.process_active_interaction(ai)

def _process_message(self, message: InboundMessage):
self._context_manager.process_command(message)

Expand Down
43 changes: 43 additions & 0 deletions irene/embedded_plugins/plugin_notification_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Добавляет API для отправки/озвучивания простых уведомлений.
"""

from typing import Optional

from irene.brain.abc import Brain, VAApiExt

name = "notification_api"
version = "0.1.0"

_brain: Optional[Brain] = None


def get_brain(nxt, *args, **kwargs):
global _brain

b = nxt(*args, **kwargs)
if _brain is None:
_brain = b
return b


def register_fastapi_endpoints(router, *_args, **_kwargs) -> None:
from fastapi import APIRouter, Body, HTTPException
from pydantic import BaseModel, Field

r: APIRouter = router

class NotificationModel(BaseModel):
text: str = Field(
title="Текст уведомления"
)

@r.post('/notify', name="Отправка уведомления")
def notify(notification: NotificationModel = Body()):
if _brain is None:
raise HTTPException(503, "Мозг не найден")

def interaction(va: VAApiExt):
va.say(notification.text)

_brain.submit_active_interaction(interaction)

0 comments on commit 9e7e3c1

Please sign in to comment.