audio-scribe 0.1.2__tar.gz → 0.1.3__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/PKG-INFO +5 -6
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/README.md +4 -5
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/setup.py +1 -1
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/__init__.py +1 -1
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/PKG-INFO +5 -6
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_auth.py +73 -2
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_models.py +38 -2
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_utils.py +26 -1
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/setup.cfg +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/auth.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/config.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/models.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/transcriber.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/utils.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/SOURCES.txt +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/dependency_links.txt +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/entry_points.txt +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/requires.txt +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/top_level.txt +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_config.py +0 -0
- {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_transcriber.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: audio_scribe
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: A command-line tool for audio transcription with Whisper and Pyannote.
|
5
5
|
Home-page: https://gitlab.genomicops.cloud/genomicops/audio-scribe
|
6
6
|
Author: Gurasis Osahan
|
@@ -48,13 +48,12 @@ Dynamic: summary
|
|
48
48
|
|
49
49
|
**A Command-Line Tool for Audio Transcription and Speaker Diarization Using OpenAI Whisper and Pyannote**
|
50
50
|
|
51
|
-
[![License](https://img.shields.io/
|
52
|
-
![Coverage](https://img.shields.io/badge/coverage-
|
53
|
-
[![
|
51
|
+
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
52
|
+
![Coverage](https://img.shields.io/badge/coverage-98.1%25-brightgreen)
|
53
|
+
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
54
|
+
![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)
|
54
55
|
[![PyPI Version](https://badge.fury.io/py/audio-scribe.svg)](https://badge.fury.io/py/audio-scribe)
|
55
56
|
[![Python Versions](https://img.shields.io/pypi/pyversions/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
56
|
-
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
57
|
-
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
58
57
|
<!-- [![Coverage Report](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/coverage.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main) -->
|
59
58
|
|
60
59
|
## Overview
|
@@ -2,13 +2,12 @@
|
|
2
2
|
|
3
3
|
**A Command-Line Tool for Audio Transcription and Speaker Diarization Using OpenAI Whisper and Pyannote**
|
4
4
|
|
5
|
-
[![License](https://img.shields.io/
|
6
|
-
![Coverage](https://img.shields.io/badge/coverage-
|
7
|
-
[![
|
5
|
+
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
6
|
+
![Coverage](https://img.shields.io/badge/coverage-98.1%25-brightgreen)
|
7
|
+
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
8
|
+
![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)
|
8
9
|
[![PyPI Version](https://badge.fury.io/py/audio-scribe.svg)](https://badge.fury.io/py/audio-scribe)
|
9
10
|
[![Python Versions](https://img.shields.io/pypi/pyversions/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
10
|
-
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
11
|
-
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
12
11
|
<!-- [![Coverage Report](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/coverage.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main) -->
|
13
12
|
|
14
13
|
## Overview
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name="audio_scribe",
|
8
|
-
version="0.1.
|
8
|
+
version="0.1.3",
|
9
9
|
author="Gurasis Osahan",
|
10
10
|
author_email="contact@genomicops.com",
|
11
11
|
description="A command-line tool for audio transcription with Whisper and Pyannote.",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: audio_scribe
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: A command-line tool for audio transcription with Whisper and Pyannote.
|
5
5
|
Home-page: https://gitlab.genomicops.cloud/genomicops/audio-scribe
|
6
6
|
Author: Gurasis Osahan
|
@@ -48,13 +48,12 @@ Dynamic: summary
|
|
48
48
|
|
49
49
|
**A Command-Line Tool for Audio Transcription and Speaker Diarization Using OpenAI Whisper and Pyannote**
|
50
50
|
|
51
|
-
[![License](https://img.shields.io/
|
52
|
-
![Coverage](https://img.shields.io/badge/coverage-
|
53
|
-
[![
|
51
|
+
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
52
|
+
![Coverage](https://img.shields.io/badge/coverage-98.1%25-brightgreen)
|
53
|
+
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
54
|
+
![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)
|
54
55
|
[![PyPI Version](https://badge.fury.io/py/audio-scribe.svg)](https://badge.fury.io/py/audio-scribe)
|
55
56
|
[![Python Versions](https://img.shields.io/pypi/pyversions/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
56
|
-
[![PyPI Downloads](https://img.shields.io/pypi/dm/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
57
|
-
[![PyPI License](https://img.shields.io/pypi/l/audio-scribe)](https://pypi.org/project/audio-scribe/)
|
58
57
|
<!-- [![Coverage Report](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/coverage.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main) -->
|
59
58
|
|
60
59
|
## Overview
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
import pytest
|
5
|
-
from unittest.mock import patch, MagicMock
|
5
|
+
from unittest.mock import patch, Mock, MagicMock
|
6
6
|
from pathlib import Path
|
7
7
|
from src.audio_scribe.auth import TokenManager, get_token
|
8
8
|
|
@@ -89,4 +89,75 @@ def test_encryption_different_machines(token_manager):
|
|
89
89
|
assert test_token not in stored_data
|
90
90
|
|
91
91
|
# But we can still retrieve it
|
92
|
-
assert token_manager.retrieve_token() == test_token
|
92
|
+
assert token_manager.retrieve_token() == test_token
|
93
|
+
|
94
|
+
def test_token_manager_initialization_error(token_manager, tmp_dir):
|
95
|
+
"""Test TokenManager initialization with permission errors."""
|
96
|
+
with patch('json.dump', side_effect=PermissionError), \
|
97
|
+
patch('builtins.open', create=True) as mock_open:
|
98
|
+
mock_open.return_value.__enter__ = lambda x: x
|
99
|
+
mock_open.return_value.__exit__ = Mock()
|
100
|
+
|
101
|
+
# This should handle the error gracefully
|
102
|
+
token_manager._initialize_config()
|
103
|
+
|
104
|
+
def test_token_store_permission_error(token_manager):
|
105
|
+
"""Test storing token with file permission errors."""
|
106
|
+
with patch('json.dump', side_effect=PermissionError):
|
107
|
+
assert token_manager.store_token("test-token") is False
|
108
|
+
|
109
|
+
def test_token_retrieve_corrupted_config(token_manager):
|
110
|
+
"""Test retrieving token with corrupted config file."""
|
111
|
+
# Write invalid JSON to config file
|
112
|
+
with open(token_manager.config_file, 'w') as f:
|
113
|
+
f.write("invalid json")
|
114
|
+
|
115
|
+
assert token_manager.retrieve_token() is None
|
116
|
+
|
117
|
+
def test_token_delete_permission_error(token_manager):
|
118
|
+
"""Test deleting token with permission errors."""
|
119
|
+
# First store a token
|
120
|
+
token_manager.store_token("test-token")
|
121
|
+
|
122
|
+
with patch('json.dump', side_effect=PermissionError):
|
123
|
+
assert token_manager.delete_token() is False
|
124
|
+
|
125
|
+
def test_get_token_invalid_choice(token_manager, monkeypatch):
|
126
|
+
"""Test get_token with invalid user input."""
|
127
|
+
token_manager.store_token("stored-token")
|
128
|
+
|
129
|
+
# Create a list to track input calls
|
130
|
+
inputs = []
|
131
|
+
def mock_input(prompt):
|
132
|
+
inputs.append(prompt)
|
133
|
+
if "Use the stored" in prompt:
|
134
|
+
return "invalid" if len(inputs) == 1 else "n"
|
135
|
+
if "Enter HuggingFace token" in prompt:
|
136
|
+
return "new-test-token"
|
137
|
+
if "Save token" in prompt:
|
138
|
+
return "n"
|
139
|
+
return "n" # default response
|
140
|
+
|
141
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
142
|
+
|
143
|
+
token = get_token(token_manager)
|
144
|
+
assert token == "new-test-token"
|
145
|
+
# Verify we got the expected prompts
|
146
|
+
assert len(inputs) >= 3, "Expected at least 3 prompts"
|
147
|
+
assert any("Use the stored" in prompt for prompt in inputs)
|
148
|
+
assert any("Enter HuggingFace token" in prompt for prompt in inputs)
|
149
|
+
assert any("Save token" in prompt for prompt in inputs)
|
150
|
+
|
151
|
+
def test_encryption_error_handling(token_manager):
|
152
|
+
"""Test encryption error handling in token storage."""
|
153
|
+
with patch('cryptography.fernet.Fernet.encrypt', side_effect=Exception("Encryption failed")):
|
154
|
+
assert token_manager.store_token("test-token") is False
|
155
|
+
|
156
|
+
def test_decryption_error_handling(token_manager):
|
157
|
+
"""Test decryption error handling in token retrieval."""
|
158
|
+
# Store an invalid encrypted token
|
159
|
+
config = token_manager._load_config()
|
160
|
+
config["token"] = "invalid-encrypted-data"
|
161
|
+
token_manager._save_config(config)
|
162
|
+
|
163
|
+
assert token_manager.retrieve_token() is None
|
@@ -6,7 +6,7 @@ import threading
|
|
6
6
|
import tempfile
|
7
7
|
from unittest.mock import patch, MagicMock, call
|
8
8
|
from pathlib import Path
|
9
|
-
|
9
|
+
import time
|
10
10
|
from src.audio_scribe.models import (
|
11
11
|
AudioProcessor,
|
12
12
|
TranscriptionPipeline,
|
@@ -347,4 +347,40 @@ def test_resource_monitoring_error(pipeline):
|
|
347
347
|
pipeline._update_resources(mock_bar)
|
348
348
|
|
349
349
|
# Monitoring should handle the error gracefully
|
350
|
-
mock_bar.text.assert_not_called()
|
350
|
+
mock_bar.text.assert_not_called()
|
351
|
+
|
352
|
+
def test_process_file_segment_error(pipeline, tmp_dir):
|
353
|
+
"""Test handling of segment processing errors."""
|
354
|
+
test_audio = tmp_dir / "test.wav"
|
355
|
+
test_audio.touch()
|
356
|
+
|
357
|
+
# Mock the diarization pipeline
|
358
|
+
pipeline.diarization_pipeline = MagicMock()
|
359
|
+
segments = [(MagicMock(start=0.0, end=1.0), None, "SPEAKER_1")]
|
360
|
+
pipeline.diarization_pipeline.return_value.itertracks.return_value = segments
|
361
|
+
|
362
|
+
# Mock the whisper model to raise an exception
|
363
|
+
pipeline.whisper_model = MagicMock()
|
364
|
+
pipeline.whisper_model.transcribe.side_effect = Exception("Transcription error")
|
365
|
+
|
366
|
+
with patch('src.audio_scribe.models.HAVE_PROGRESS_SUPPORT', False), \
|
367
|
+
patch('src.audio_scribe.models.AudioProcessor') as mock_audio_processor_class:
|
368
|
+
|
369
|
+
mock_audio_processor = MagicMock()
|
370
|
+
mock_audio_processor.load_audio_segment.return_value = True
|
371
|
+
mock_audio_processor_class.return_value = mock_audio_processor
|
372
|
+
|
373
|
+
# Process should complete but log the error
|
374
|
+
result = pipeline.process_file(test_audio)
|
375
|
+
assert result is False
|
376
|
+
|
377
|
+
def test_process_file_with_empty_segments(pipeline, tmp_dir):
|
378
|
+
"""Test processing when diarization returns no segments."""
|
379
|
+
test_audio = tmp_dir / "test.wav"
|
380
|
+
test_audio.touch()
|
381
|
+
|
382
|
+
pipeline.diarization_pipeline = MagicMock()
|
383
|
+
pipeline.diarization_pipeline.return_value.itertracks.return_value = []
|
384
|
+
|
385
|
+
result = pipeline.process_file(test_audio)
|
386
|
+
assert result is True
|
@@ -80,4 +80,29 @@ def test_verify_dependencies_version_mismatch():
|
|
80
80
|
def test_required_packages_configuration(package, version):
|
81
81
|
"""Test the required packages configuration."""
|
82
82
|
assert package in DependencyManager.REQUIRED_PACKAGES
|
83
|
-
assert DependencyManager.REQUIRED_PACKAGES[package] == version
|
83
|
+
assert DependencyManager.REQUIRED_PACKAGES[package] == version
|
84
|
+
|
85
|
+
def test_complete_path_with_glob_patterns():
|
86
|
+
"""Test path completion with glob patterns."""
|
87
|
+
with patch('glob.glob') as mock_glob:
|
88
|
+
mock_glob.return_value = ['/path/test*.txt']
|
89
|
+
result = complete_path('test*.txt', 0)
|
90
|
+
assert result == '/path/test*.txt'
|
91
|
+
mock_glob.assert_called_once_with('test*.txt')
|
92
|
+
|
93
|
+
def test_complete_path_permission_error():
|
94
|
+
"""Test path completion when directory access is denied."""
|
95
|
+
def mock_listdir(_):
|
96
|
+
raise OSError("Permission denied")
|
97
|
+
|
98
|
+
with patch('os.listdir', side_effect=mock_listdir):
|
99
|
+
result = complete_path('test', 0)
|
100
|
+
assert result is None
|
101
|
+
|
102
|
+
def test_complete_path_state_bounds():
|
103
|
+
"""Test path completion with state beyond available matches."""
|
104
|
+
with patch('os.listdir', return_value=['file1.txt']):
|
105
|
+
# First match should work
|
106
|
+
assert complete_path('file', 0) == 'file1.txt'
|
107
|
+
# State beyond matches should return None
|
108
|
+
assert complete_path('file', 1) is None
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|