From bb57b4d71a8e25da6c739be4e751cd7ebe7a3b64 Mon Sep 17 00:00:00 2001 From: Tonya Camille Date: Wed, 9 Nov 2022 19:11:41 -0500 Subject: [PATCH] Adding new feature non-async prerecorded --- README.md | 22 ++++++++++++ deepgram/_utils.py | 44 ++++++++++++++++++++++++ deepgram/transcription.py | 71 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ce66877..83139d58 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,28 @@ pip install deepgram-sdk #### Transcribe an Existing File or Pre-recorded Audio +```python +from deepgram import Deepgram +import json + +DEEPGRAM_API_KEY = 'YOUR_API_KEY' +PATH_TO_FILE = 'some/file.wav' + +def main(): + # Initializes the Deepgram SDK + deepgram = Deepgram(DEEPGRAM_API_KEY) + # Open the audio file + with open(PATH_TO_FILE, 'rb') as audio: + # ...or replace mimetype as appropriate + source = {'buffer': audio, 'mimetype': 'audio/wav'} + response = deepgram.transcription.sync_prerecorded(source, {'punctuate': True}) + print(json.dumps(response, indent=4)) + +main() +``` + +#### Transcribe an Existing File or Pre-recorded Audio Asynchronously + ```python from deepgram import Deepgram import asyncio, json diff --git a/deepgram/_utils.py b/deepgram/_utils.py index fd9cef70..0dc9c245 100644 --- a/deepgram/_utils.py +++ b/deepgram/_utils.py @@ -1,6 +1,8 @@ from typing import Any, Union, Optional, IO, Mapping, Tuple, List, cast import aiohttp import urllib.parse +import urllib.request +import urllib.error import io import json import re @@ -117,6 +119,48 @@ async def attempt(): return await attempt() +def _sync_request( + path: str, options: Options, + method: str = 'GET', payload: Payload = None, + headers: Optional[Mapping[str, str]] = None +) -> Any: + if headers is None: + headers = {} + destination = cast(str, options.get('api_url', DEFAULT_ENDPOINT)) + path + updated_headers = _prepare_headers(options, headers) + + def attempt(): + req = urllib.request.Request( + destination, + data=_normalize_payload(payload), + headers=updated_headers, + method=method) + try: + with urllib.request.urlopen(req) as resp: + content = resp.read().strip() + if not content: + return None + body = json.loads(content) + if body.get('error'): + raise Exception(f'DG: {content}') + return body + except urllib.error.URLError as exc: + raise (Exception(f'DG: {exc}') if exc.status < 500 else exc) + + tries = RETRY_COUNT + while tries > 0: + try: + return attempt() + except urllib.error.URLError as exc: + if isinstance(payload, io.IOBase): + raise exc # stream is now invalid as payload + # the way aiohttp handles streaming form data + # means that just seeking this back still runs into issues + tries -= 1 + continue + return attempt() + + async def _socket_connect( path: str, options: Options, headers: Optional[Mapping[str, str]] = None ) -> websockets.client.WebSocketClientProtocol: diff --git a/deepgram/transcription.py b/deepgram/transcription.py index 48788534..62188aa8 100644 --- a/deepgram/transcription.py +++ b/deepgram/transcription.py @@ -9,11 +9,11 @@ TranscriptionSource, PrerecordedTranscriptionResponse, LiveTranscriptionResponse, Metadata, EventHandler) from ._enums import LiveTranscriptionEvent -from ._utils import _request, _make_query_string, _socket_connect +from ._utils import _request, _sync_request, _make_query_string, _socket_connect class PrerecordedTranscription: - """This class provides an interface for doing transcription on prerecorded audio files.""" + """This class provides an interface for doing transcription asynchronously on prerecorded audio files.""" _root = "/listen" @@ -63,6 +63,58 @@ async def __call__( ) +class SyncPrerecordedTranscription: + """This class provides an interface for doing transcription synchronously on prerecorded audio files.""" + + _root = "/listen" + + def __init__(self, options: Options, + transcription_options: PrerecordedOptions) -> None: + """ + This function initializes the options and transcription_options for the PrerecordedTranscription class. + + :param options:Options: Used to Pass in the options for the transcription. + :param transcription_options:PrerecordedOptions: Used to Specify the transcription options for a prerecorded audio file. + :return: Nothing. + + """ + + self.options = options + self.transcription_options = transcription_options + + def __call__( + self, source: TranscriptionSource + ) -> PrerecordedTranscriptionResponse: + + """ + The __call__ function is a special method that allows the class to be called + as a function. This is useful for creating instances of the class, where we can + call `SyncPrerecordedTranscription()` and pass in arguments to set up an instance of + the class. For example: + + sync_prerecorded_transcription = SyncPrerecordedTranscription(...) + + :param source:TranscriptionSource: Used to Pass in the audio file. + :return: A `prerecordedtranscriptionresponse` object, which contains the transcription results. + + """ + + if 'buffer' in source and 'mimetype' not in source: + raise Exception( + 'DG: Mimetype must be provided if the source is bytes' + ) + payload = cast( + Union[bytes, Dict], + source.get('buffer', {'url': source.get('url')}) + ) + content_type = cast(str, source.get('mimetype', 'application/json')) + return _sync_request( + f'{self._root}{_make_query_string(self.transcription_options)}', + self.options, method='POST', payload=payload, + headers={'Content-Type': content_type} + ) + + class LiveTranscription: """ This class allows you to perform live transcription by connecting to Deepgram's Transcribe Streaming API. @@ -283,6 +335,21 @@ async def prerecorded( self.options, full_options )(source) + + def sync_prerecorded( + self, source: TranscriptionSource, + options: PrerecordedOptions = None, **kwargs + ) -> PrerecordedTranscriptionResponse: + """Retrieves a transcription for an already-existing audio file, + local or web-hosted.""" + if options is None: + options = {} + full_options = cast(PrerecordedOptions, {**options, **kwargs}) + return SyncPrerecordedTranscription( + self.options, full_options + )(source) + + async def live( self, options: LiveOptions = None, **kwargs ) -> LiveTranscription: