Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit Test cases clean up, bug fixes, new functionality #231

Merged
merged 6 commits into from
Jun 10, 2024
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
4 changes: 2 additions & 2 deletions app/transcribe/audio_transcriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ def transcribe_audio_queue(self, audio_queue: queue.Queue):
while True:
who_spoke, data, time_spoken = audio_queue.get()
logger.info(f'Transcribe Audio Queue. Current time: {datetime.datetime.utcnow()} '
f'- Time Spoken: {time_spoken} by : {who_spoke}, queue_backlog - '
f'{audio_queue.qsize()}')
f'- Time Spoken: {time_spoken} by : {who_spoke}, queue_backlog - '
f'{audio_queue.qsize()}')
self._update_last_sample_and_phrase_status(who_spoke, data, time_spoken)
source_info = self.audio_sources_properties[who_spoke]

Expand Down
59 changes: 59 additions & 0 deletions app/transcribe/tests/test_selectable_text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import unittest
from tkinter import Tk
# from customtkinter import CTk

# Assuming SelectableTextComponent is defined in a module named selectable_text_component
from app.transcribe.uicomp.selectable_text import SelectableText


class TestSelectableText(unittest.TestCase):
def setUp(self):
# Set up a root window and the component for testing
self.root = Tk()
self.root.withdraw() # Hide the root window
self.component = SelectableText(self.root)
self.component.pack()

def tearDown(self):
self.component.destroy()
self.root.destroy()

def test_insert_text_at_top(self):
self.component.add_text_to_top("First line at top")
result = self.component.text_widget.get("1.0", "2.0").strip()
self.assertEqual(result, "First line at top")

def test_insert_text_at_bottom(self):
self.component.add_text_to_bottom("First line at bottom")
result = self.component.text_widget.get("end-2l", "end-1l").strip()
self.assertEqual(result, "First line at bottom")

def test_scroll_to_top(self):
self.component.add_text_to_top("Line 1\nLine 2\nLine 3\n")
self.component.scroll_to_bottom()
self.component.scroll_to_top()
self.assertEqual(self.component.text_widget.yview()[0], 0.0)

def test_scroll_to_bottom(self):
self.component.add_text_to_bottom("Line 1\nLine 2\nLine 3\n")
self.component.scroll_to_bottom()
self.assertEqual(self.component.text_widget.yview()[1], 1.0)

def test_delete_last_two_rows(self):
self.component.add_text_to_bottom("Line 1")
self.component.add_text_to_bottom("Line 2")
self.component.add_text_to_bottom("Line 3")
self.component.delete_last_2_row()
result = self.component.text_widget.get("1.0", "end").strip()
self.assertEqual(result, "Line 1")

def test_clear_all_text(self):
self.component.add_text_to_bottom("Line 1")
self.component.add_text_to_bottom("Line 2")
self.component.clear_all_text()
result = self.component.text_widget.get("1.0", "end").strip()
self.assertEqual(result, "")


if __name__ == '__main__':
unittest.main()
5 changes: 3 additions & 2 deletions custom_speech_recognition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,8 @@ def recognize_ibm(self, audio_data, key, language="en-US", show_all=False):
transcription = []
confidence = None
for utterance in result["results"]:
if "alternatives" not in utterance: raise UnknownValueError()
if "alternatives" not in utterance:
raise UnknownValueError()
for hypothesis in utterance["alternatives"]:
if "transcript" in hypothesis:
transcription.append(hypothesis["transcript"])
Expand Down Expand Up @@ -1605,7 +1606,7 @@ def recognize_whisper(self, audio_data, model="base", show_dict=False, load_opti
task="translate" if translate else None,
# fp16=torch.cuda.is_available(),
fp16=False,
temperature=0,
# temperature=0,
**transcribe_options
)

Expand Down
5 changes: 4 additions & 1 deletion sdk/transcriber_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def __init__(self, stt_model_config: dict):
self.model_name = self.model + ".pt"
self.model_filename = os.path.join(MODELS_DIR, model_filename)
self.download_model()
self.audio_model = whisper.load_model(self.model_filename)
self.audio_model: whisper.Whisper = whisper.load_model(self.model_filename)
print(f'[INFO] Speech To Text - Whisper using GPU: {str(torch.cuda.is_available())}')
openai.api_key = stt_model_config["api_key"]

Expand Down Expand Up @@ -142,6 +142,9 @@ def get_transcription(self, wav_file_path) -> dict:
"""Get transcription from the provided audio file
"""
try:
# For translation provide a decode_option for task=translate
# options = {}
# options['task'] = 'translate'
result = self.audio_model.transcribe(wav_file_path,
fp16=False,
language=self.lang,
Expand Down
Binary file added tests/english.wav
Binary file not shown.
127 changes: 80 additions & 47 deletions tests/test_recognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@

class TestRecognition(unittest.TestCase):
def setUp(self):
self.AUDIO_FILE_EN = os.path.join(os.path.dirname(os.path.realpath(__file__)), "english.wav")
self.AUDIO_FILE_FR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "french.aiff")
self.AUDIO_FILE_ZH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "chinese.flac")
self.AUDIO_FILE_EN = os.path.join(os.path.dirname(os.path.realpath(__file__)),
"english.wav")
self.AUDIO_FILE_FR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
"french.aiff")
self.AUDIO_FILE_ZH = os.path.join(os.path.dirname(os.path.realpath(__file__)),
"chinese.flac")
self.WHISPER_CONFIG = {"temperature": 0}

# def test_sphinx_english(self):
Expand All @@ -21,82 +24,112 @@ def setUp(self):

def test_google_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
with sr.AudioFile(self.AUDIO_FILE_EN) as source:
audio = r.record(source)
result = r.recognize_google(audio)
self.assertIn(result, ["1 2"])
self.assertIn(result, ["1 2"], f'Expected ["1 2"] got {result}')

def test_google_french(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_FR) as source: audio = r.record(source)
self.assertEqual(r.recognize_google(audio, language="fr-FR"), u"et c'est la dictée numéro 1")
with sr.AudioFile(self.AUDIO_FILE_FR) as source:
audio = r.record(source)
self.assertEqual(r.recognize_google(audio, language="fr-FR"), "et c'est la dictée numéro 1")

def test_google_chinese(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_ZH) as source: audio = r.record(source)
self.assertEqual(r.recognize_google(audio, language="zh-CN"), u"砸自己的脚")
# def test_google_chinese(self):
# r = sr.Recognizer()
# with sr.AudioFile(self.AUDIO_FILE_ZH) as source: audio = r.record(source)
# self.assertEqual(r.recognize_google(audio, language="zh-CN"), "砸自己的脚")

@unittest.skipUnless("WIT_AI_KEY" in os.environ, "requires Wit.ai key to be specified in WIT_AI_KEY environment variable")
@unittest.skipUnless("WIT_AI_KEY" in os.environ, "requires Wit.ai key to be specified in WIT_AI_KEY "
+ "environment variable")
def test_wit_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
with sr.AudioFile(self.AUDIO_FILE_EN) as source:
audio = r.record(source)
self.assertEqual(r.recognize_wit(audio, key=os.environ["WIT_AI_KEY"]), "one two three")

@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be specified in BING_KEY environment variable")
@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be "
+ "specified in BING_KEY environment variable")
def test_bing_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
with sr.AudioFile(self.AUDIO_FILE_EN) as source:
audio = r.record(source)
self.assertEqual(r.recognize_bing(audio, key=os.environ["BING_KEY"]), "123.")

@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be specified in BING_KEY environment variable")
@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be "
+ "specified in BING_KEY environment variable")
def test_bing_french(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_FR) as source: audio = r.record(source)
self.assertEqual(r.recognize_bing(audio, key=os.environ["BING_KEY"], language="fr-FR"), u"Essaye la dictée numéro un.")
with sr.AudioFile(self.AUDIO_FILE_FR) as source:
audio = r.record(source)
self.assertEqual(r.recognize_bing(audio, key=os.environ["BING_KEY"], language="fr-FR"),
"Essaye la dictée numéro un.")

@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be specified in BING_KEY environment variable")
@unittest.skipUnless("BING_KEY" in os.environ, "requires Microsoft Bing Voice Recognition key to be "
+ "specified in BING_KEY environment variable")
def test_bing_chinese(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_ZH) as source: audio = r.record(source)
self.assertEqual(r.recognize_bing(audio, key=os.environ["BING_KEY"], language="zh-CN"), u"砸自己的脚。")
with sr.AudioFile(self.AUDIO_FILE_ZH) as source:
audio = r.record(source)
self.assertEqual(r.recognize_bing(audio, key=os.environ["BING_KEY"], language="zh-CN"), "砸自己的脚。")

@unittest.skipUnless("HOUNDIFY_CLIENT_ID" in os.environ and "HOUNDIFY_CLIENT_KEY" in os.environ, "requires Houndify client ID and client key to be specified in HOUNDIFY_CLIENT_ID and HOUNDIFY_CLIENT_KEY environment variables")
@unittest.skipUnless("HOUNDIFY_CLIENT_ID" in os.environ and "HOUNDIFY_CLIENT_KEY" in os.environ,
"requires Houndify client ID and client key to be specified in HOUNDIFY_CLIENT_ID "
+ "and HOUNDIFY_CLIENT_KEY environment variables")
def test_houndify_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
self.assertEqual(r.recognize_houndify(audio, client_id=os.environ["HOUNDIFY_CLIENT_ID"], client_key=os.environ["HOUNDIFY_CLIENT_KEY"]), "one two three")

@unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ, "requires IBM Speech to Text username and password to be specified in IBM_USERNAME and IBM_PASSWORD environment variables")
def test_ibm_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"], password=os.environ["IBM_PASSWORD"]), "one two three ")

@unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ, "requires IBM Speech to Text username and password to be specified in IBM_USERNAME and IBM_PASSWORD environment variables")
def test_ibm_french(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_FR) as source: audio = r.record(source)
self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"], password=os.environ["IBM_PASSWORD"], language="fr-FR"), u"si la dictée numéro un ")

@unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ, "requires IBM Speech to Text username and password to be specified in IBM_USERNAME and IBM_PASSWORD environment variables")
def test_ibm_chinese(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_ZH) as source: audio = r.record(source)
self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"], password=os.environ["IBM_PASSWORD"], language="zh-CN"), u"砸 自己 的 脚 ")
with sr.AudioFile(self.AUDIO_FILE_EN) as source:
audio = r.record(source)
self.assertEqual(r.recognize_houndify(audio, client_id=os.environ["HOUNDIFY_CLIENT_ID"],
client_key=os.environ["HOUNDIFY_CLIENT_KEY"]),
"one two three")

# All IBM related test cases are commented because the parameters are incorrect
# @unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ,
# "requires IBM Speech to Text username and password to be specified in IBM_USERNAME \
# and IBM_PASSWORD environment variables")
# def test_ibm_english(self):
# r = sr.Recognizer()
# with sr.AudioFile(self.AUDIO_FILE_EN) as source:
# audio = r.record(source)
# self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"],
# password=os.environ["IBM_PASSWORD"]), "one two three ")

# @unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ, "requires IBM Speech"
# + " to Text username and password to be specified in IBM_USERNAME and IBM_PASSWORD"
# + " environment variables")
# def test_ibm_french(self):
# r = sr.Recognizer()
# with sr.AudioFile(self.AUDIO_FILE_FR) as source:
# audio = r.record(source)
# self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"], password=os.environ["IBM_PASSWORD"], language="fr-FR"), "si la dictée numéro un ")

# @unittest.skipUnless("IBM_USERNAME" in os.environ and "IBM_PASSWORD" in os.environ, "requires IBM Speech to Text username and password to be specified in IBM_USERNAME and IBM_PASSWORD environment variables")
# def test_ibm_chinese(self):
# r = sr.Recognizer()
# with sr.AudioFile(self.AUDIO_FILE_ZH) as source:
# audio = r.record(source)
# self.assertEqual(r.recognize_ibm(audio, username=os.environ["IBM_USERNAME"], password=os.environ["IBM_PASSWORD"], language="zh-CN"), "砸 自己 的 脚 ")

def test_whisper_english(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_EN) as source: audio = r.record(source)
with sr.AudioFile(self.AUDIO_FILE_EN) as source:
audio = r.record(source)
self.assertEqual(r.recognize_whisper(audio, language="english", **self.WHISPER_CONFIG), " 1, 2, 3.")

def test_whisper_french(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_FR) as source: audio = r.record(source)
self.assertEqual(r.recognize_whisper(audio, language="french", **self.WHISPER_CONFIG), " et c'est la dictée numéro 1.")
with sr.AudioFile(self.AUDIO_FILE_FR) as source:
audio = r.record(source)
self.assertEqual(r.recognize_whisper(audio, language="french", **self.WHISPER_CONFIG),
" et c'est la dictée numéro 1.")

def test_whisper_chinese(self):
r = sr.Recognizer()
with sr.AudioFile(self.AUDIO_FILE_ZH) as source: audio = r.record(source)
self.assertEqual(r.recognize_whisper(audio, model="small", language="chinese", **self.WHISPER_CONFIG), u"砸自己的腳")
with sr.AudioFile(self.AUDIO_FILE_ZH) as source:
audio = r.record(source)
self.assertEqual(r.recognize_whisper(audio, model="small", language="chinese", **self.WHISPER_CONFIG), "砸自己的腳")


if __name__ == "__main__":
unittest.main()
4 changes: 2 additions & 2 deletions tsutils/app_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
import logging
from logging import handlers
import logging.config
import constants
from tsutils import utilities

root_logger: logging.Logger = logging.getLogger(name=constants.LOG_NAME)
root_logger: logging.Logger = logging.getLogger(name='Transcribe')
AUDIO_PLAYER_LOGGER: str = 'audio_player'
TRANSCRIBER_LOGGER: str = 'transcriber'
GPT_RESPONDER_LOGGER: str = 'gpt_responder'
Expand Down Expand Up @@ -93,6 +92,7 @@ def setup_logging(log_file_name: str):
'class': 'logging.FileHandler',
'filename': log_file_name,
'formatter': 'standard',
'encoding': 'utf-8'
},
},
'loggers': {
Expand Down
Empty file added tsutils/tests/__init__.py
Empty file.
21 changes: 21 additions & 0 deletions tsutils/tests/test_duration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest
from unittest.mock import patch
import datetime
from tsutils.duration import Duration


class TestDuration(unittest.TestCase):
"""Unit Tests for Duration class
"""

@patch('datetime.datetime')
def test_enter_method(self, mock_datetime):
"""Test that __enter__ method records the start time correctly."""
mock_datetime.now.return_value = datetime.datetime(2023, 1, 1, 12, 0, 0)
duration = Duration()
with duration:
self.assertEqual(duration.start, datetime.datetime(2023, 1, 1, 12, 0, 0))


if __name__ == '__main__':
unittest.main()
50 changes: 50 additions & 0 deletions tsutils/tests/test_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import unittest
from unittest.mock import patch
from tsutils.utilities import (
merge, incrementing_filename, naturalsize,
download_using_bits, ensure_directory_exists
)


class TestFunctions(unittest.TestCase):

def test_merge(self):
first = {'a': 1, 'b': {'c': 3}}
second = {'b': {'d': 4}, 'e': 5}
result = merge(first, second)
self.assertEqual(result, {'a': 1, 'b': {'c': 3, 'd': 4}, 'e': 5})

@patch('os.path.exists', side_effect=[True, True, False])
def test_incrementing_filename(self, mock_exists):
result = incrementing_filename('file', 'txt')
self.assertEqual(result, 'file-2.txt')

def test_naturalsize(self):
result = naturalsize(3000000)
self.assertEqual(result, '3.0 MB')
result = naturalsize(300, False, True)
self.assertEqual(result, '300.0B', f'Expected 300.0B got {result}')

@patch('subprocess.check_output')
def test_download_using_bits(self, mock_subproc):
download_using_bits('https://github.com/vivekuppal/transcribe/archive/refs/heads/main.zip', 'transcribe.zip')
mock_subproc.assert_called_once_with(['powershell',
'-NoProfile',
'-ExecutionPolicy',
'Bypass',
'-Command',
'Start-BitsTransfer',
'-Source',
'https://github.com/vivekuppal/transcribe/archive/refs/heads/main.zip',
'-Destination',
'transcribe.zip'])

@patch('os.makedirs')
@patch('os.path.exists', return_value=False)
def test_ensure_directory_exists(self, mock_exists, mock_makedirs):
ensure_directory_exists('.')
mock_makedirs.assert_called_once_with('.')


if __name__ == '__main__':
unittest.main()
6 changes: 3 additions & 3 deletions tsutils/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ def ensure_directory_exists(directory_path: str):
"""
if not os.path.exists(directory_path):
os.makedirs(directory_path)
print(f"Directory '{directory_path}' created.")
else:
print(f"Directory '{directory_path}' already exists.")
# print(f"Directory '{directory_path}' created.")
# else:
# print(f"Directory '{directory_path}' already exists.")


def get_data_path(app_name, filename=''):
Expand Down