Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 60 additions & 11 deletions deepgram/audio/microphone/microphone.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import threading
import pyaudio
from array import array
from sys import byteorder
import logging, verboselogs

from .errors import DeepgramMicrophoneError

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
CHUNK = 8000
CHUNK = 8194


class Microphone:
Expand All @@ -23,8 +23,18 @@ class Microphone:
"""

def __init__(
self, push_callback, format=FORMAT, rate=RATE, chunk=CHUNK, channels=CHANNELS
self,
push_callback,
verbose=logging.WARNING,
format=FORMAT,
rate=RATE,
chunk=CHUNK,
channels=CHANNELS,
):
self.logger = logging.getLogger(__name__)
self.logger.addHandler(logging.StreamHandler())
self.logger.setLevel(verbose)

self.audio = pyaudio.PyAudio()
self.chunk = chunk
self.rate = rate
Expand All @@ -34,20 +44,36 @@ def __init__(
self.stream = None

def is_active(self):
self.logger.debug("Microphone.is_active ENTER")
if self.stream is None:
self.logger.error("stream is None")
self.logger.debug("Microphone.is_active LEAVE")
return False
return self.stream.is_active()

val = self.stream.is_active()
self.logger.info("is_active: %s", val)
self.logger.debug("Microphone.is_active LEAVE")
return

def start(self):
self.logger.debug("Microphone.start ENTER")

if self.stream is not None:
self.logger.error("stream is None")
self.logger.debug("Microphone.start LEAVE")
raise DeepgramMicrophoneError("Microphone already started")

self.logger.info("format: %s", self.format)
self.logger.info("channels: %d", self.channels)
self.logger.info("rate: %d", self.rate)
self.logger.info("chunk: %d", self.chunk)

self.stream = self.audio.open(
format=self.format,
channels=self.channels,
rate=self.rate,
input=True,
frames_per_buffer=CHUNK,
frames_per_buffer=self.chunk,
)

self.exit = False
Expand All @@ -57,7 +83,12 @@ def start(self):
self.thread = threading.Thread(target=self.processing)
self.thread.start()

self.logger.notice("start succeeded")
self.logger.debug("Microphone.start LEAVE")

def processing(self):
self.logger.debug("Microphone.processing ENTER")

try:
while True:
data = self.stream.read(self.chunk)
Expand All @@ -66,27 +97,45 @@ def processing(self):
localExit = self.exit
self.lock.release()
if localExit:
self.logger.info("exit is True")
break
if data is None:
self.logger.info("data is None")
continue

if inspect.iscoroutinefunction(self.push_callback):
self.logger.verbose("async/await callback")
asyncio.run(self.push_callback(data))
else:
self.logger.verbose("regular threaded callback")
self.push_callback(data)

self.logger.notice("processing exiting...")
self.logger.debug("Microphone.processing LEAVE")

except Exception as e:
print(f"Error while sending: {str(e)}")
self.logger.error("Error while sending: %s", str(e))
self.logger.debug("Microphone.processing LEAVE")
raise

def finish(self):
self.logger.debug("Microphone.finish ENTER")

self.lock.acquire()
self.logger.notice("signal exit")
self.exit = True
self.lock.release()

self.thread.join()
self.thread = None
if self.thread is not None:
self.thread.join()
self.thread = None
self.logger.notice("processing/send thread joined")

self.stream.stop_stream()
self.stream.close()
self.stream = None
if self.stream is not None:
self.stream.stop_stream()
self.stream.close()
self.stream = None
self.logger.notice("stream/recv thread joined")

self.logger.notice("finish succeeded")
self.logger.debug("Microphone.finish LEAVE")
30 changes: 25 additions & 5 deletions deepgram/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

from typing import Optional
from importlib import import_module
import logging, verboselogs

from .clients.listen import ListenClient
from .clients.listen import ListenClient, PreRecordedClient
from .clients.manage.client import ManageClient
from .clients.onprem.client import OnPremClient

Expand All @@ -30,10 +31,13 @@ class DeepgramClient:
listen: Returns a ListenClient instance for interacting with Deepgram's transcription services.
manage: Returns a ManageClient instance for managing Deepgram resources.
onprem: Returns an OnPremClient instance for interacting with Deepgram's on-premises API.

"""

def __init__(self, api_key: str, config: Optional[DeepgramClientOptions] = None):
verboselogs.install()
self.logger = logging.getLogger(__name__)
self.logger.addHandler(logging.StreamHandler())

if not api_key:
raise DeepgramApiKeyError("Deepgram API key is required")

Expand All @@ -44,6 +48,8 @@ def __init__(self, api_key: str, config: Optional[DeepgramClientOptions] = None)
config.set_apikey(self.api_key)
self.config = config

self.logger.setLevel(logging.SPAM)

@property
def listen(self):
return ListenClient(self.config)
Expand All @@ -59,6 +65,9 @@ def onprem(self):
# INTERNAL CLASSES
class Version:
def __init__(self, config, parent: str):
self.logger = logging.getLogger(__name__)
self.logger.addHandler(logging.StreamHandler())
self.logger.setLevel(config.verbose)
self.config = config
self.parent = parent

Expand All @@ -75,8 +84,11 @@ def __init__(self, config, parent: str):
# raise DeepgramModuleError("Invalid parent")

def v(self, version: str = ""):
# print(f"version: {version}")
self.logger.debug("Version.v ENTER")
self.logger.info("version: %s", version)
if len(version) == 0:
self.logger.error("version is empty")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Invalid module version")

className = ""
Expand All @@ -86,22 +98,30 @@ def v(self, version: str = ""):
case "onprem":
className = "OnPremClient"
case _:
self.logger.error("parent unknown: %s", self.parent)
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Invalid parent type")

# create class path
path = f"deepgram.clients.{self.parent}.v{version}.client"
# print(f"path: {path}")
# print(f"className: {className}")
self.logger.info("path: %s", path)
self.logger.info("className: %s", className)

# import class
mod = import_module(path)
if mod is None:
self.logger.error("module path is None")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Unable to find package")

my_class = getattr(mod, className)
if my_class is None:
self.logger.error("my_class is None")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Unable to find class")

# instantiate class
myClass = my_class(self.config)
self.logger.notice("Version.v succeeded")
self.logger.debug("Version.v LEAVE")
return myClass
21 changes: 18 additions & 3 deletions deepgram/clients/listen.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: MIT

from importlib import import_module
import logging, verboselogs

from ..options import DeepgramClientOptions

Expand Down Expand Up @@ -30,6 +31,9 @@ def legacylive(self):
# INTERNAL CLASSES
class Version:
def __init__(self, config, parent: str):
self.logger = logging.getLogger(__name__)
self.logger.addHandler(logging.StreamHandler())
self.logger.setLevel(config.verbose)
self.config = config
self.parent = parent

Expand All @@ -46,8 +50,11 @@ def __init__(self, config, parent: str):
# raise DeepgramModuleError("Invalid parent")

def v(self, version: str = ""):
# print(f"version: {version}")
self.logger.debug("Version.v ENTER")
self.logger.info("version: %s", version)
if len(version) == 0:
self.logger.error("version is empty")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Invalid module version")

className = ""
Expand All @@ -57,22 +64,30 @@ def v(self, version: str = ""):
case "prerecorded":
className = "PreRecordedClient"
case _:
self.logger.error("parent unknown: %s", self.parent)
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Invalid parent type")

# create class path
path = f"deepgram.clients.{self.parent}.v{version}.client"
# print(f"path: {path}")
# print(f"className: {className}")
self.logger.info("path: %s", path)
self.logger.info("className: %s", className)

# import class
mod = import_module(path)
if mod is None:
self.logger.error("module path is None")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Unable to find package")

my_class = getattr(mod, className)
if my_class is None:
self.logger.error("my_class is None")
self.logger.debug("Version.v LEAVE")
raise DeepgramModuleError("Unable to find class")

# instantiate class
myClass = my_class(self.config)
self.logger.notice("Version.v succeeded")
self.logger.debug("Version.v LEAVE")
return myClass
Loading