diff --git a/deepgram/client.py b/deepgram/client.py index 857c37cd..7751cf42 100644 --- a/deepgram/client.py +++ b/deepgram/client.py @@ -7,6 +7,8 @@ import logging, verboselogs import os +from .clients.live.client import LiveOptions +from .clients.prerecorded.client import PrerecordedOptions from .clients.listen import ListenClient, PreRecordedClient from .clients.manage.client import ManageClient from .clients.onprem.client import OnPremClient @@ -34,7 +36,9 @@ class DeepgramClient: onprem: Returns an OnPremClient instance for interacting with Deepgram's on-premises API. """ - def __init__(self, api_key: str, config: Optional[DeepgramClientOptions] = None): + def __init__( + self, api_key: str = "", config: Optional[DeepgramClientOptions] = None + ): verboselogs.install() self.logger = logging.getLogger(__name__) self.logger.addHandler(logging.StreamHandler()) @@ -42,6 +46,8 @@ def __init__(self, api_key: str, config: Optional[DeepgramClientOptions] = None) 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) + if not api_key: + self.logger.warning("WARNING: API key is missing") self.api_key = api_key if config is None: # Use default configuration diff --git a/deepgram/clients/live/helpers.py b/deepgram/clients/live/helpers.py index 5eb7b68d..0017f3d1 100644 --- a/deepgram/clients/live/helpers.py +++ b/deepgram/clients/live/helpers.py @@ -3,21 +3,25 @@ # SPDX-License-Identifier: MIT from urllib.parse import urlparse, urlunparse, parse_qs, urlencode +from typing import Dict +from .errors import DeepgramError -def append_query_params(url, params=""): + +def append_query_params(url, params): parsed_url = urlparse(url) query_params = parse_qs(parsed_url.query) - if params: - for key, value in params.items(): - if isinstance(value, bool): - value = str(value).lower() - if isinstance(value, list): - for item in value: - query_params[key] = query_params.get(key, []) + [str(item)] - else: - query_params[key] = [str(value)] + for key, value in params.items(): + if value is None: + continue + if isinstance(value, bool): + value = str(value).lower() + if isinstance(value, list): + for item in value: + query_params[key] = query_params.get(key, []) + [str(item)] + else: + query_params[key] = [str(value)] updated_query_string = urlencode(query_params, doseq=True) updated_url = parsed_url._replace(query=updated_query_string).geturl() diff --git a/deepgram/clients/live/v1/client.py b/deepgram/clients/live/v1/client.py index 7c1b7757..9e0705b7 100644 --- a/deepgram/clients/live/v1/client.py +++ b/deepgram/clients/live/v1/client.py @@ -60,6 +60,9 @@ def start(self, options: LiveOptions = None): self.logger.info("options: %s", options) self.options = options + if isinstance(options, LiveOptions): + self.logger.info("LiveOptions switching class -> json") + self.options = self.options.to_dict() if self._socket is not None: self.logger.error("socket is already initialized") diff --git a/deepgram/clients/live/v1/legacy_client.py b/deepgram/clients/live/v1/legacy_client.py index bd2e6971..ecbcb68e 100644 --- a/deepgram/clients/live/v1/legacy_client.py +++ b/deepgram/clients/live/v1/legacy_client.py @@ -55,6 +55,10 @@ async def __call__(self, options: LiveOptions = None): self.logger.info("options: %s", options) self.options = options + if isinstance(options, LiveOptions): + self.logger.info("LiveOptions switching class -> json") + self.options = self.options.to_dict() + url_with_params = append_query_params(self.websocket_url, self.options) try: self._socket = await _socket_connect(url_with_params, self.config.headers) diff --git a/deepgram/clients/live/v1/options.py b/deepgram/clients/live/v1/options.py index e5efe0b0..c783aff4 100644 --- a/deepgram/clients/live/v1/options.py +++ b/deepgram/clients/live/v1/options.py @@ -2,28 +2,36 @@ # Use of this source code is governed by a MIT license that can be found in the LICENSE file. # SPDX-License-Identifier: MIT -from typing import List, TypedDict +from dataclasses import dataclass +from dataclasses_json import dataclass_json +from typing import List, Optional -class LiveOptions(TypedDict, total=False): - callback: str - channels: int - diarize: bool - encoding: str - endpointing: int - interim_results: bool - keywords: str - language: str - model: str - multichannel: bool - numerals: bool - punctuate: bool - profanity_filter: bool - redact: bool - replace: str - sample_rate: int - search: str - smart_format: bool - tag: list - tier: str - version: str +@dataclass_json +@dataclass +class LiveOptions: + callback: Optional[str] = None + channels: Optional[int] = None + diarize: Optional[bool] = None + encoding: Optional[str] = None + endpointing: Optional[str] = None + interim_results: Optional[bool] = None + keywords: Optional[str] = None + language: Optional[str] = None + model: Optional[str] = None + multichannel: Optional[bool] = None + numerals: Optional[bool] = None + punctuate: Optional[bool] = None + profanity_filter: Optional[bool] = None + redact: Optional[bool] = None + replace: Optional[str] = None + sample_rate: Optional[int] = None + search: Optional[str] = None + smart_format: Optional[bool] = None + tag: Optional[list] = None + tier: Optional[str] = None + version: Optional[str] = None + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] diff --git a/deepgram/clients/manage/client.py b/deepgram/clients/manage/client.py index ec9c8d18..410c0dba 100644 --- a/deepgram/clients/manage/client.py +++ b/deepgram/clients/manage/client.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT from .v1.client import ManageClient as ManageClientLatest -from .v1.response import ( +from .v1.options import ( ProjectOptions as ProjectOptionsLatest, KeyOptions as KeyOptionsLatest, ScopeOptions as ScopeOptionsLatest, diff --git a/deepgram/clients/manage/v1/client.py b/deepgram/clients/manage/v1/client.py index 136453c3..7b3132ef 100644 --- a/deepgram/clients/manage/v1/client.py +++ b/deepgram/clients/manage/v1/client.py @@ -24,7 +24,7 @@ BalancesResponse, Balance, ) -from .response import ( +from .options import ( ProjectOptions, KeyOptions, ScopeOptions, diff --git a/deepgram/clients/manage/v1/options.py b/deepgram/clients/manage/v1/options.py new file mode 100644 index 00000000..56cd9dcb --- /dev/null +++ b/deepgram/clients/manage/v1/options.py @@ -0,0 +1,115 @@ +# 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 + +from dataclasses import dataclass +from dataclasses_json import dataclass_json +from datetime import datetime +from typing import TypedDict, List, Optional + +# Input + + +@dataclass_json +@dataclass +class ProjectOptions: + name: Optional[str] = "" + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] + + +@dataclass_json +@dataclass +class KeyOptions: + comment: Optional[str] = "" + time_to_live_in_seconds: Optional[int] = 0 + expiration_date: Optional[str] = "" + scopes: Optional[List[str]] = None + tags: Optional[List[str]] = None + + def __getitem__(self, key): + _dict = self.to_dict() + if _dict["scopes"] is not None: + _dict["scopes"] = [str(scopes) for scopes in _dict["scopes"]] + if _dict["tags"] is not None: + _dict["tags"] = [str(tags) for tags in _dict["tags"]] + return _dict[key] + + +@dataclass_json +@dataclass +class ScopeOptions: + scope: Optional[str] = "" + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] + + +@dataclass_json +@dataclass +class InviteOptions: + email: Optional[str] = "" + scope: Optional[str] = "" + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] + + +@dataclass_json +@dataclass +class UsageRequestOptions: + start: Optional[str] = "" + end: Optional[str] = "" + limit: Optional[int] = 0 + status: Optional[str] = "" + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] + + +@dataclass_json +@dataclass +class UsageSummaryOptions: + start: Optional[str] = "" + end: Optional[str] = "" + accessor: Optional[str] = "" + tag: Optional[str] = "" + method: Optional[str] = "" + model: Optional[str] = "" + multichannel: Optional[bool] = False + interim_results: Optional[bool] = False + punctuate: Optional[bool] = False + ner: Optional[bool] = False + utterances: Optional[bool] = False + replace: Optional[bool] = False + profanity_filter: Optional[bool] = False + keywords: Optional[bool] = False + detect_topics: Optional[bool] = False + diarize: Optional[bool] = False + search: Optional[bool] = False + redact: Optional[bool] = False + alternatives: Optional[bool] = False + numerals: Optional[bool] = False + smart_format: Optional[bool] = False + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] + + +@dataclass_json +@dataclass +class UsageFieldsOptions: + start: Optional[str] = "" + end: Optional[str] = "" + + def __getitem__(self, key): + _dict = self.to_dict() + if _dict["details"] is not None: + _dict["details"] = Details.from_dict(_dict["details"]) + return _dict[key] diff --git a/deepgram/clients/manage/v1/response.py b/deepgram/clients/manage/v1/response.py index cc5fbdcb..5ef0eb7d 100644 --- a/deepgram/clients/manage/v1/response.py +++ b/deepgram/clients/manage/v1/response.py @@ -48,16 +48,6 @@ def __getitem__(self, key): return _dict[key] -@dataclass_json -@dataclass -class ProjectOptions: - name: Optional[str] = "" - - def __getitem__(self, key): - _dict = self.to_dict() - return _dict[key] - - # Members @@ -131,24 +121,6 @@ def __getitem__(self, key): return _dict[key] -@dataclass_json -@dataclass -class KeyOptions: - comment: Optional[str] = "" - time_to_live_in_seconds: Optional[int] = 0 - expiration_date: Optional[str] = "" - scopes: Optional[List[str]] = None - tags: Optional[List[str]] = None - - def __getitem__(self, key): - _dict = self.to_dict() - if _dict["scopes"] is not None: - _dict["scopes"] = [str(scopes) for scopes in _dict["scopes"]] - if _dict["tags"] is not None: - _dict["tags"] = [str(tags) for tags in _dict["tags"]] - return _dict[key] - - # Scopes @dataclass_json @dataclass @@ -162,16 +134,6 @@ def __getitem__(self, key): return _dict[key] -@dataclass_json -@dataclass -class ScopeOptions: - scope: Optional[str] = "" - - def __getitem__(self, key): - _dict = self.to_dict() - return _dict[key] - - # Invites @@ -198,17 +160,6 @@ def __getitem__(self, key): return _dict[key] -@dataclass_json -@dataclass -class InviteOptions: - email: Optional[str] = "" - scope: Optional[str] = "" - - def __getitem__(self, key): - _dict = self.to_dict() - return _dict[key] - - # Usage @dataclass_json @dataclass @@ -313,45 +264,6 @@ def __getitem__(self, key): return _dict[key] -class UsageRequestOptions: - start: Optional[str] = "" - end: Optional[str] = "" - limit: Optional[int] = 0 - status: Optional[str] = "" - - def __getitem__(self, key): - _dict = self.to_dict() - return _dict[key] - - -class UsageSummaryOptions: - start: Optional[str] = "" - end: Optional[str] = "" - accessor: Optional[str] = "" - tag: Optional[str] = "" - method: Optional[str] = "" - model: Optional[str] = "" - multichannel: Optional[bool] = False - interim_results: Optional[bool] = False - punctuate: Optional[bool] = False - ner: Optional[bool] = False - utterances: Optional[bool] = False - replace: Optional[bool] = False - profanity_filter: Optional[bool] = False - keywords: Optional[bool] = False - detect_topics: Optional[bool] = False - diarize: Optional[bool] = False - search: Optional[bool] = False - redact: Optional[bool] = False - alternatives: Optional[bool] = False - numerals: Optional[bool] = False - smart_format: Optional[bool] = False - - def __getitem__(self, key): - _dict = self.to_dict() - return _dict[key] - - @dataclass_json @dataclass class Results: @@ -436,17 +348,6 @@ def __getitem__(self, key): return _dict[key] -class UsageFieldsOptions: - start: Optional[str] = "" - end: Optional[str] = "" - - def __getitem__(self, key): - _dict = self.to_dict() - if _dict["details"] is not None: - _dict["details"] = Details.from_dict(_dict["details"]) - return _dict[key] - - # Billing diff --git a/deepgram/clients/prerecorded/v1/client.py b/deepgram/clients/prerecorded/v1/client.py index a452c99b..cadf7fbf 100644 --- a/deepgram/clients/prerecorded/v1/client.py +++ b/deepgram/clients/prerecorded/v1/client.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: MIT import logging, verboselogs +import inspect from ...abstract_client import AbstractRestfulClient from ..errors import DeepgramTypeError @@ -66,6 +67,9 @@ async def transcribe_url( self.logger.info("url: %s", url) self.logger.info("source: %s", source) self.logger.info("options: %s", options) + if isinstance(options, PrerecordedOptions): + self.logger.info("PrerecordedOptions switching class -> json") + options = options.to_json() res = PrerecordedResponse.from_json(await self.post(url, options, json=body)) self.logger.verbose("result: %s", res) self.logger.notice("transcribe_url succeeded") @@ -113,6 +117,9 @@ async def transcribe_url_callback( self.logger.info("url: %s", url) self.logger.info("source: %s", source) self.logger.info("options: %s", options) + if isinstance(options, PrerecordedOptions): + self.logger.info("PrerecordedOptions switching class -> json") + options = options.to_json() json = await self.post(url, options, json=body) self.logger.info("json: %s", json) res = AsyncPrerecordedResponse.from_json(json) @@ -159,6 +166,9 @@ async def transcribe_file( self.logger.info("url: %s", url) self.logger.info("options: %s", options) + if isinstance(options, PrerecordedOptions): + self.logger.info("PrerecordedOptions switching class -> json") + options = options.to_json() json = await self.post(url, options, content=body) self.logger.info("json: %s", json) res = PrerecordedResponse.from_json(json) @@ -209,6 +219,9 @@ async def transcribe_file_callback( self.logger.info("url: %s", url) self.logger.info("options: %s", options) + if isinstance(options, PrerecordedOptions): + self.logger.info("PrerecordedOptions switching class -> json") + options = options.to_json() json = await self.post(url, options, json=body) self.logger.info("json: %s", json) res = AsyncPrerecordedResponse.from_json(json) diff --git a/deepgram/clients/prerecorded/v1/options.py b/deepgram/clients/prerecorded/v1/options.py index 4b27a703..eb23bb7a 100644 --- a/deepgram/clients/prerecorded/v1/options.py +++ b/deepgram/clients/prerecorded/v1/options.py @@ -2,31 +2,39 @@ # Use of this source code is governed by a MIT license that can be found in the LICENSE file. # SPDX-License-Identifier: MIT -from typing import Union, List, TypedDict +from dataclasses import dataclass +from dataclasses_json import dataclass_json +from typing import Union, List, TypedDict, Optional -class PrerecordedOptions(TypedDict, total=False): - alternatives: int - callback: str - detect_entities: bool - detect_language: bool - detect_topics: bool - diarize: bool - keywords: Union[list, str] - language: str - model: str - multichannel: bool - numerals: bool - paragraphs: bool - profanity_filter: bool - punctuate: bool - redact: Union[List[str], bool, str] - replace: Union[list, str] - search: Union[list, str] - smart_format: bool - summarize: Union[bool, str] - tag: list - tier: str - utt_split: int - utterances: bool - version: str +@dataclass_json +@dataclass +class PrerecordedOptions: + alternatives: Optional[int] = None + callback: Optional[str] = None + detect_entities: Optional[bool] = None + detect_language: Optional[bool] = None + detect_topics: Optional[bool] = None + diarize: Optional[bool] = None + keywords: Optional[Union[list, str]] = None + language: Optional[str] = None + model: Optional[str] = None + multichannel: Optional[bool] = None + numerals: Optional[bool] = None + paragraphs: Optional[bool] = None + profanity_filter: Optional[bool] = None + punctuate: Optional[bool] = None + redact: Optional[Union[List[str], bool, str]] = None + replace: Optional[Union[list, str]] = None + search: Optional[Union[list, str]] = None + smart_format: Optional[bool] = None + summarize: Optional[Union[bool, str]] = None + tag: Optional[list] = None + tier: Optional[str] = None + utt_split: Optional[int] = None + utterances: Optional[bool] = None + version: Optional[str] = None + + def __getitem__(self, key): + _dict = self.to_dict() + return _dict[key] diff --git a/examples/manage/balances/main.py b/examples/manage/balances/main.py index 5476e869..9f693913 100644 --- a/examples/manage/balances/main.py +++ b/examples/manage/balances/main.py @@ -12,15 +12,12 @@ load_dotenv() -# environment variables -API_KEY = os.getenv("DG_API_KEY") - # Create a Deepgram client using the API key config: DeepgramClientOptions = DeepgramClientOptions( verbose=logging.SPAM, ) -deepgram: DeepgramClient = DeepgramClient(API_KEY, config) +deepgram: DeepgramClient = DeepgramClient("", config) async def main(): diff --git a/examples/manage/invitations/main.py b/examples/manage/invitations/main.py index 67ff3f94..6eb04afb 100644 --- a/examples/manage/invitations/main.py +++ b/examples/manage/invitations/main.py @@ -11,11 +11,8 @@ load_dotenv() -# environment variables -API_KEY = os.getenv("DG_API_KEY") - # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/manage/keys/main.py b/examples/manage/keys/main.py index 98904d86..3562e6e8 100644 --- a/examples/manage/keys/main.py +++ b/examples/manage/keys/main.py @@ -11,11 +11,8 @@ load_dotenv() -# environment variables -API_KEY = os.getenv("DG_API_KEY") - # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/manage/members/main.py b/examples/manage/members/main.py index fff54816..6a8b3512 100644 --- a/examples/manage/members/main.py +++ b/examples/manage/members/main.py @@ -12,11 +12,10 @@ load_dotenv() # environment variables -API_KEY = os.getenv("DG_API_KEY") DELETE_MEMBER_BY_EMAIL = "enter-your-email@gmail.com" # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/manage/projects/main.py b/examples/manage/projects/main.py index 22977cbe..6a06671a 100644 --- a/examples/manage/projects/main.py +++ b/examples/manage/projects/main.py @@ -12,11 +12,10 @@ load_dotenv() # environment variables -API_KEY = os.getenv("DG_API_KEY") DELETE_PROJECT_BY_NAME = os.getenv("DG_DELETE_PROJECT_BY_NAME") # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/manage/scopes/main.py b/examples/manage/scopes/main.py index b4d90d90..7be04f9a 100644 --- a/examples/manage/scopes/main.py +++ b/examples/manage/scopes/main.py @@ -12,11 +12,10 @@ load_dotenv() # environment variables -API_KEY = os.getenv("DG_API_KEY") MEMBER_BY_EMAIL = "enter-your-email@gmail.com" # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/manage/usage/main.py b/examples/manage/usage/main.py index 9b8b9398..564b21c6 100644 --- a/examples/manage/usage/main.py +++ b/examples/manage/usage/main.py @@ -16,11 +16,8 @@ load_dotenv() -# environment variables -API_KEY = os.getenv("DG_API_KEY") - # Create a Deepgram client using the API key -deepgram: DeepgramClient = DeepgramClient(API_KEY) +deepgram: DeepgramClient = DeepgramClient() async def main(): diff --git a/examples/prerecorded/file/main.py b/examples/prerecorded/file/main.py index 9fb85cb3..b130efca 100644 --- a/examples/prerecorded/file/main.py +++ b/examples/prerecorded/file/main.py @@ -16,7 +16,6 @@ load_dotenv() -API_KEY = os.getenv("DG_API_KEY") AUDIO_FILE = "preamble.wav" # Create a Deepgram client using the API key @@ -24,14 +23,14 @@ verbose=logging.SPAM, ) -options: PrerecordedOptions = PrerecordedOptions( +options = PrerecordedOptions( model="nova", smart_format="true", summarize="v2", ) # STEP 1 Create a Deepgram client using the API key (optional - add config options) -deepgram: DeepgramClient = DeepgramClient(API_KEY, config) +deepgram: DeepgramClient = DeepgramClient("", config) # STEP 2 Call the transcribe_file method on the prerecorded class diff --git a/examples/prerecorded/url/main.py b/examples/prerecorded/url/main.py index 5f3a83e4..d3127fd2 100644 --- a/examples/prerecorded/url/main.py +++ b/examples/prerecorded/url/main.py @@ -10,7 +10,6 @@ load_dotenv() -API_KEY = os.getenv("DG_API_KEY") AUDIO_URL = { "url": "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav" } @@ -22,7 +21,7 @@ } # STEP 1 Create a Deepgram client using the API key (optional - add config options) -deepgram = DeepgramClient(API_KEY) +deepgram = DeepgramClient() # STEP 2 Call the transcribe_url method on the prerecorded class diff --git a/examples/streaming/http/main.py b/examples/streaming/http/main.py index 558afb99..dcab8be3 100644 --- a/examples/streaming/http/main.py +++ b/examples/streaming/http/main.py @@ -16,11 +16,9 @@ # URL for the realtime streaming audio you would like to transcribe URL = "http://stream.live.vc.bbcmedia.co.uk/bbc_world_service" -deepgram_api_key = os.getenv("DG_API_KEY") - async def main(): - deepgram: DeepgramClient = DeepgramClient(deepgram_api_key) + deepgram: DeepgramClient = DeepgramClient() # Create a websocket connection to Deepgram try: diff --git a/examples/streaming/microphone/main.py b/examples/streaming/microphone/main.py index 11a3421c..8a90d2f6 100644 --- a/examples/streaming/microphone/main.py +++ b/examples/streaming/microphone/main.py @@ -4,6 +4,7 @@ import os from dotenv import load_dotenv +import logging, verboselogs from deepgram import ( DeepgramClient, @@ -15,15 +16,19 @@ load_dotenv() -options: LiveOptions = { - "punctuate": True, - "language": "en-US", - "encoding": "linear16", - "channels": 1, - "sample_rate": 16000, -} - -deepgram_api_key = os.getenv("DG_API_KEY") +# example of setting up a client config +# config = DeepgramClientOptions( +# verbose=logging.SPAM, +# options={'keepalive': 'true'} +# ) + +options = LiveOptions( + punctuate=True, + language="en-US", + encoding="linear16", + channels=1, + sample_rate=16000, +) def on_message(result=None): @@ -52,8 +57,10 @@ def on_error(error=None): def main(): - # config: DeepgramClientOptions = DeepgramClientOptions(options={'keepalive': 'true'}) - deepgram: DeepgramClient = DeepgramClient(deepgram_api_key) + # to specify a client config + # deepgram: DeepgramClient = DeepgramClient("", config) + # otherwise, use default config + deepgram: DeepgramClient = DeepgramClient() try: # Create a websocket connection to Deepgram