Initial revision
[python_utils.git] / google_assistant.py
1 #!/usr/bin/env python3
2
3 import logging
4 from typing import NamedTuple
5
6 import requests
7 import speech_recognition as sr  # type: ignore
8
9 import config
10
11 logger = logging.getLogger(__name__)
12
13 parser = config.add_commandline_args(
14     f"Google Assistant ({__file__})",
15     "Args related to contacting the Google Assistant",
16 )
17 parser.add_argument(
18     "--google_assistant_bridge",
19     type=str,
20     default="http://kiosk.house:3000",
21     metavar="URL",
22     help="How to contact the Google Assistant bridge"
23 )
24 parser.add_argument(
25     "--google_assistant_username",
26     type=str,
27     metavar="GOOGLE_ACCOUNT",
28     default="scott.gasch",
29     help="The user account for talking to Google Assistant"
30 )
31
32
33 class GoogleResponse(NamedTuple):
34     success: bool
35     response: str
36     audio_url: str
37     audio_transcription: str
38
39     def __repr__(self):
40         return f"""
41 success: {self.success}
42 response: {self.response}
43 audio_transcription: {self.audio_transcription}
44 audio_url: {self.audio_url}"""
45
46
47 def tell_google(cmd: str, *, recognize_speech=True) -> GoogleResponse:
48     return ask_google(cmd, recognize_speech=recognize_speech)
49
50
51 def ask_google(cmd: str, *, recognize_speech=True) -> GoogleResponse:
52     payload = {
53         "command": cmd,
54         "user": config.config['google_assistant_username'],
55     }
56     url = f"{config.config['google_assistant_bridge']}/assistant"
57     r = requests.post(url, json=payload)
58     success = False
59     response = ""
60     audio = ""
61     audio_transcription = ""
62     if r.status_code == 200:
63         j = r.json()
64         success = bool(j["success"])
65         response = j["response"] if success else j["error"]
66         audio = f"{config.config['google_assistant_bridge']}{j['audio']}"
67         if recognize_speech:
68             recognizer = sr.Recognizer()
69             r = requests.get(audio)
70             if r.status_code == 200:
71                 raw = r.content
72                 speech = sr.AudioData(
73                     frame_data=raw,
74                     sample_rate=24000,
75                     sample_width=2,
76                 )
77                 audio_transcription = recognizer.recognize_google(
78                     speech,
79                 )
80     else:
81         logger.error(
82             f'HTTP request to {url} with {payload} failed; code {r.status_code}'
83         )
84     return GoogleResponse(
85         success=success,
86         response=response,
87         audio_url=audio,
88         audio_transcription=audio_transcription,
89     )