Skip to content

Commit

Permalink
Add ping
Browse files Browse the repository at this point in the history
  • Loading branch information
synesthesiam committed Jan 15, 2024
1 parent 77de6f6 commit afd7387
Show file tree
Hide file tree
Showing 14 changed files with 222 additions and 5 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name="wyoming",
version="1.4.2",
version="1.5.0",
description="Protocol for Rhasspy Voice Assistant",
url="http://github.com/rhasspy/rhasspy3",
author="Michael Hansen",
Expand Down
3 changes: 2 additions & 1 deletion wyoming/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
from . import pyaudioop as audioop # type: ignore[no-redef]

from .event import Event, Eventable
from .util.dataclasses_json import DataClassJsonMixin

_CHUNK_TYPE = "audio-chunk"
_START_TYPE = "audio-start"
_STOP_TYPE = "audio-stop"


@dataclass
class AudioFormat:
class AudioFormat(DataClassJsonMixin):
"""Base class for events with audio format information."""

rate: int
Expand Down
3 changes: 3 additions & 0 deletions wyoming/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ class Error(Eventable):
"""Error with text and an optional code."""

text: str
"""Human-readable error message."""

code: Optional[str] = None
"""Machine-readable error code."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand Down
10 changes: 10 additions & 0 deletions wyoming/handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@

@dataclass
class Handled(Eventable):
"""Result of successful intent handling."""

text: Optional[str] = None
"""Human-readable response."""

context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand All @@ -35,8 +40,13 @@ def from_event(event: Event) -> "Handled":

@dataclass
class NotHandled(Eventable):
"""Result of intent handling failure."""

text: Optional[str] = None
"""Human-readable response."""

context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand Down
73 changes: 72 additions & 1 deletion wyoming/info.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Information about available services/artifacts."""
"""Information about available services, models, etc.."""
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

from .audio import AudioFormat
from .event import Event, Eventable
from .util.dataclasses_json import DataClassJsonMixin

Expand All @@ -12,6 +13,8 @@

@dataclass
class Describe(Eventable):
"""Request info message."""

@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _DESCRIBE_TYPE
Expand All @@ -26,108 +29,176 @@ def from_event(event: Event) -> "Describe":

@dataclass
class Attribution(DataClassJsonMixin):
"""Attribution for an artifact."""

name: str
"""Who made it."""

url: str
"""Where it's from."""


@dataclass
class Artifact(DataClassJsonMixin):
"""Information about a service, model, etc.."""

name: str
"""Name/id of artifact."""

attribution: Attribution
"""Who made the artifact and where it's from."""

installed: bool
"""True if the artifact is currently installed."""

description: Optional[str]
"""Human-readable description of the artifact."""


# -----------------------------------------------------------------------------


@dataclass
class AsrModel(Artifact):
"""Speech-to-text model."""

languages: List[str]
"""List of supported model languages."""


@dataclass
class AsrProgram(Artifact):
"""Speech-to-text service."""

models: List[AsrModel]
"""List of available models."""


# -----------------------------------------------------------------------------


@dataclass
class TtsVoiceSpeaker(DataClassJsonMixin):
"""Individual speaker in a multi-speaker voice."""

name: str
"""Name/id of speaker."""


@dataclass
class TtsVoice(Artifact):
"""Text-to-speech voice."""

languages: List[str]
"""List of languages available in the voice."""

speakers: Optional[List[TtsVoiceSpeaker]] = None
"""List of individual speakers in the voice."""


@dataclass
class TtsProgram(Artifact):
"""Text-to-speech service."""

voices: List[TtsVoice]
"""List of available voices."""


# -----------------------------------------------------------------------------


@dataclass
class HandleModel(Artifact):
"""Intent handling model."""

languages: List[str]
"""List of supported languages in the model."""


@dataclass
class HandleProgram(Artifact):
"""Intent handling service."""

models: List[HandleModel]
"""List of available models."""


# -----------------------------------------------------------------------------


@dataclass
class WakeModel(Artifact):
"""Wake word detection model."""

languages: List[str]
"""List of languages supported by the model."""


@dataclass
class WakeProgram(Artifact):
"""Wake word detection service."""

models: List[WakeModel]
"""List of available models."""


# -----------------------------------------------------------------------------


@dataclass
class IntentModel(Artifact):
"""Intent recognition model."""

languages: List[str]
"""List of languages supported by the model."""


@dataclass
class IntentProgram(Artifact):
"""Intent recognition service."""

models: List[IntentModel]
"""List of available models."""


# -----------------------------------------------------------------------------


@dataclass
class Satellite(Artifact):
"""Satellite information."""

area: Optional[str] = None
"""Name of the area the satellite is in."""

snd_format: Optional[AudioFormat] = None
"""Format of the satellite's audio output."""


# -----------------------------------------------------------------------------


@dataclass
class Info(Eventable):
"""Response to describe message with information about available services, models, etc."""

asr: List[AsrProgram] = field(default_factory=list)
"""Speech-to-text services."""

tts: List[TtsProgram] = field(default_factory=list)
"""Text-to-speech services."""

handle: List[HandleProgram] = field(default_factory=list)
"""Intent handling services."""

intent: List[IntentProgram] = field(default_factory=list)
"""Intent recognition services."""

wake: List[WakeProgram] = field(default_factory=list)
"""Wake word detection services."""

satellite: Optional[Satellite] = None
"""Satellite information."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand Down
21 changes: 21 additions & 0 deletions wyoming/intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@

@dataclass
class Entity:
"""Named entity with a value."""

name: str
value: Optional[Any] = None


@dataclass
class Recognize(Eventable):
"""Request to recognize an event from text."""

text: str
"""Text with intent in natural language."""

context: Optional[Dict[str, Any]] = None
"""Context from previous interactions."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand All @@ -39,10 +46,19 @@ def from_event(event: Event) -> "Recognize":

@dataclass
class Intent(Eventable):
"""Result of successful intent recognition."""

name: str
"""Name of intent."""

entities: List[Entity] = field(default_factory=list)
"""Named entities with values."""

text: Optional[str] = None
"""Human-readable response."""

context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand Down Expand Up @@ -96,8 +112,13 @@ def to_rhasspy(self) -> Dict[str, Any]:

@dataclass
class NotRecognized(Eventable):
"""Result of intent recognition failure."""

text: Optional[str] = None
"""Human-readable response."""

context: Optional[Dict[str, Any]] = None
"""Context for next interaction."""

@staticmethod
def is_type(event_type: str) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions wyoming/mic.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@


class MicProcessAsyncClient(AsyncClient, contextlib.AbstractAsyncContextManager):
"""Context manager for getting microphone audio from an external program."""

def __init__(
self,
rate: int,
Expand Down
52 changes: 52 additions & 0 deletions wyoming/ping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Ping/pong messages."""
from dataclasses import dataclass
from typing import Optional

from .event import Event, Eventable

_PING_TYPE = "ping"
_PONG_TYPE = "pong"


@dataclass
class Ping(Eventable):
"""Request pong message."""

text: Optional[str] = None
"""Text to copy to response."""

@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _PING_TYPE

def event(self) -> Event:
return Event(
type=_PING_TYPE,
data={"text": self.text},
)

@staticmethod
def from_event(event: Event) -> "Ping":
return Ping(text=event.data.get("text"))


@dataclass
class Pong(Eventable):
"""Response to ping message."""

text: Optional[str] = None
"""Text copied from request."""

@staticmethod
def is_type(event_type: str) -> bool:
return event_type == _PONG_TYPE

def event(self) -> Event:
return Event(
type=_PONG_TYPE,
data={"text": self.text},
)

@staticmethod
def from_event(event: Event) -> "Pong":
return Pong(text=event.data.get("text"))
Loading

0 comments on commit afd7387

Please sign in to comment.