diff --git a/deepgram/__init__.py b/deepgram/__init__.py index d0416dd5..2b719137 100644 --- a/deepgram/__init__.py +++ b/deepgram/__init__.py @@ -7,7 +7,8 @@ # entry point for the deepgram python sdk from .client import Deepgram, DeepgramClient -from .options import DeepgramClientOptions +from .options import DeepgramClientOptions, ClientOptionsFromEnv +import logging, verboselogs # listen client from .client import ListenClient diff --git a/deepgram/client.py b/deepgram/client.py index eb6aa5f8..97713027 100644 --- a/deepgram/client.py +++ b/deepgram/client.py @@ -130,10 +130,6 @@ class DeepgramClient: 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: # Default to `None` for on-prem instances where an API key is not required api_key = os.getenv("DEEPGRAM_API_KEY", None) @@ -147,8 +143,6 @@ def __init__( config.set_apikey(self.api_key) self.config = config - self.logger.setLevel(logging.SPAM) - @property def listen(self): return ListenClient(self.config) diff --git a/deepgram/options.py b/deepgram/options.py index 15b169e7..7b2c0fb6 100644 --- a/deepgram/options.py +++ b/deepgram/options.py @@ -4,7 +4,9 @@ import logging, verboselogs from typing import Dict, Optional +from .errors import DeepgramApiKeyError import re +import os class DeepgramClientOptions: @@ -19,7 +21,7 @@ class DeepgramClientOptions: url: (Optional) The URL used to interact with production, On-prem, and other Deepgram environments. Defaults to `api.deepgram.com`. headers: (Optional) Headers for initializing the client. options: (Optional) Additional options for initializing the client. - """ + """ def __init__( self, @@ -29,6 +31,10 @@ def __init__( headers: Dict[str, str] = None, options: Dict[str, str] = None, ): + verboselogs.install() + self.logger = logging.getLogger(__name__) + self.logger.addHandler(logging.StreamHandler()) + self.verbose = verbose self.api_key = api_key self._update_headers(headers=headers) @@ -59,3 +65,23 @@ def _update_headers(self, headers: Optional[Dict[str, str]] = None): # Overwrite / add any headers that were passed in if headers: self.headers.update(headers) + + +class ClientOptionsFromEnv(DeepgramClientOptions): + def __init__( + self, + verbose: int = logging.WARNING, + headers: Dict[str, str] = None, + options: Dict[str, str] = None, + ): + apiKey = os.getenv("DEEPGRAM_API_KEY", None) + if apiKey is None: + raise DeepgramApiKeyError("Deepgram API KEY is not set") + + url = os.getenv("DEEPGRAM_URL", None) + if url is None: + url = "api.deepgram.com" + + super().__init__( + api_key=apiKey, url=url, verbose=verbose, headers=headers, options=options + ) diff --git a/examples/advanced/README.md b/examples/advanced/README.md new file mode 100644 index 00000000..067ba840 --- /dev/null +++ b/examples/advanced/README.md @@ -0,0 +1,20 @@ +# Advanced Examples + +These are advanced examples that should not be used unless you understand advanced concepts in the Python language or with programming in general. + +## Prerequisites + +Please see the README.md one folder up in the `examples` folder. + +## Advanced Examples + +Here are some advanced examples: + +- Prerecorded + + - [examples/advanced/prerecorded/direct-invocation](https://github.com/deepgram/deepgram-python-sdk/blob/main/examples/advanced/prerecorded/direct-invocation/main.py) - Directly instaniate the Prerecorded classes in this SDK + +- Streaming: + + - [examples/advanced/streaming/direct-invocation](https://github.com/deepgram/deepgram-python-sdk/blob/main/examples/advanced/streaming/direct-invocation/main.py) - Directly instaniate the Live/Streaming classes in this SDK + - [examples/advanced/streaming/microphone-inheritance](https://github.com/deepgram/deepgram-python-sdk/blob/main/examples/advanced/streaming//microphone-inheritance/main.py) - Extend the LiveClient class \ No newline at end of file diff --git a/examples/advanced/prerecorded/direct-invocation/main.py b/examples/advanced/prerecorded/direct-invocation/main.py new file mode 100644 index 00000000..ea0e3663 --- /dev/null +++ b/examples/advanced/prerecorded/direct-invocation/main.py @@ -0,0 +1,44 @@ +# Copyright 2023 Deepgram SDK contributors. All Rights Reserved. +# Use of this source code is governed by a MIT license that can be found in the LICENSE file. +# SPDX-License-Identifier: MIT + +import os +from dotenv import load_dotenv +import logging, verboselogs +import traceback + +from deepgram import ClientOptionsFromEnv, PrerecordedOptions, PreRecordedClient + +load_dotenv() + +AUDIO_URL = { + "url": "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav" +} + + +def main(): + try: + # STEP 1 Create a Deepgram PreRecordedClient using a specific config + # config = ClientOptionsFromEnv( + # verbose=verboselogs.NOTICE, + # ) + # asyncClient = PreRecordedClient(config) + # OR just use the default config + asyncClient = PreRecordedClient(ClientOptionsFromEnv()) + + # STEP 2 Call the transcribe_url method on the prerecorded class + options = PrerecordedOptions( + model="nova", + smart_format=True, + summarize="v2", + ) + response = asyncClient.transcribe_url(AUDIO_URL, options) + print(response.to_json(indent=4)) + + except Exception as e: + print(f"Exception: {e}") + traceback.print_exc() + + +if __name__ == "__main__": + main() diff --git a/examples/advanced/streaming/direct-invocation/main.py b/examples/advanced/streaming/direct-invocation/main.py new file mode 100644 index 00000000..8cfc88b6 --- /dev/null +++ b/examples/advanced/streaming/direct-invocation/main.py @@ -0,0 +1,95 @@ +# Copyright 2023 Deepgram SDK contributors. All Rights Reserved. +# Use of this source code is governed by a MIT license that can be found in the LICENSE file. +# SPDX-License-Identifier: MIT + +import httpx +from dotenv import load_dotenv +import logging, verboselogs +import threading + +from deepgram import ( + LiveClient, + ClientOptionsFromEnv, + LiveTranscriptionEvents, + LiveOptions, +) + +load_dotenv() + +# URL for the realtime streaming audio you would like to transcribe +URL = "http://stream.live.vc.bbcmedia.co.uk/bbc_world_service" + + +def main(): + try: + # STEP 1 Create a Deepgram LiveClient using a specific config + # config = ClientOptionsFromEnv( + # verbose=logging.DEBUG, options={"keepalive": "true"} + # ) + # liveClient = LiveClient("", config) + # OR just use the default config + liveClient = LiveClient(ClientOptionsFromEnv()) + + def on_message(self, result, **kwargs): + sentence = result.channel.alternatives[0].transcript + if len(sentence) == 0: + return + print(f"speaker: {sentence}") + + def on_metadata(self, metadata, **kwargs): + print(f"\n\n{metadata}\n\n") + + def on_utterance_end(self, utterance_end, **kwargs): + print(f"\n\n{utterance_end}\n\n") + + def on_error(self, error, **kwargs): + print(f"\n\n{error}\n\n") + + liveClient.on(LiveTranscriptionEvents.Transcript, on_message) + liveClient.on(LiveTranscriptionEvents.Metadata, on_metadata) + liveClient.on(LiveTranscriptionEvents.UtteranceEnd, on_utterance_end) + liveClient.on(LiveTranscriptionEvents.Error, on_error) + + # connect to websocket + options = LiveOptions(model="nova", interim_results=False, language="en-US") + liveClient.start(options) + + lock_exit = threading.Lock() + exit = False + + # define a worker thread + def myThread(): + with httpx.stream("GET", URL) as r: + for data in r.iter_bytes(): + lock_exit.acquire() + if exit: + break + lock_exit.release() + + liveClient.send(data) + + # start the worker thread + myHttp = threading.Thread(target=myThread) + myHttp.start() + + # signal finished + input("Press Enter to stop recording...\n\n") + lock_exit.acquire() + exit = True + lock_exit.release() + + # Wait for the HTTP thread to close and join + myHttp.join() + + # Indicate that we've finished + liveClient.finish() + + print("Finished") + + except Exception as e: + print(f"Could not open socket: {e}") + return + + +if __name__ == "__main__": + main() diff --git a/examples/advanced/microphone-inheritance/README.md b/examples/advanced/streaming/microphone-inheritance/README.md similarity index 100% rename from examples/advanced/microphone-inheritance/README.md rename to examples/advanced/streaming/microphone-inheritance/README.md diff --git a/examples/advanced/microphone-inheritance/main.py b/examples/advanced/streaming/microphone-inheritance/main.py similarity index 91% rename from examples/advanced/microphone-inheritance/main.py rename to examples/advanced/streaming/microphone-inheritance/main.py index 01576bbc..f980c187 100644 --- a/examples/advanced/microphone-inheritance/main.py +++ b/examples/advanced/streaming/microphone-inheritance/main.py @@ -7,8 +7,7 @@ from time import sleep from deepgram import ( - DeepgramClient, - DeepgramClientOptions, + ClientOptionsFromEnv, LiveTranscriptionEvents, LiveClient, LiveOptions, @@ -24,7 +23,7 @@ # more complex example class MyLiveClient(LiveClient): - def __init__(self, config: DeepgramClientOptions): + def __init__(self, config: LiveClient): super().__init__(config) super().on(LiveTranscriptionEvents.Transcript, self.on_message) super().on(LiveTranscriptionEvents.Metadata, self.on_metadata) @@ -65,14 +64,13 @@ def on_error(self, parent, error, **kwargs): def main(): try: # example of setting up a client config. logging values: WARNING, VERBOSE, DEBUG, SPAM - # config = DeepgramClientOptions( + # config = ClientOptionsFromEnv( # verbose=logging.DEBUG, # options={"keepalive": "true"} # ) - # deepgram: DeepgramClient = DeepgramClient("", config) + # liveClient = MyLiveClient(config) # otherwise, use default config - deepgram = DeepgramClient() - liveClient = MyLiveClient(deepgram.config) + liveClient = MyLiveClient(ClientOptionsFromEnv()) options = LiveOptions( punctuate=True,