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.
Files changed (21) hide show
  1. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/PKG-INFO +5 -6
  2. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/README.md +4 -5
  3. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/setup.py +1 -1
  4. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/__init__.py +1 -1
  5. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/PKG-INFO +5 -6
  6. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_auth.py +73 -2
  7. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_models.py +38 -2
  8. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_utils.py +26 -1
  9. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/setup.cfg +0 -0
  10. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/auth.py +0 -0
  11. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/config.py +0 -0
  12. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/models.py +0 -0
  13. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/transcriber.py +0 -0
  14. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe/utils.py +0 -0
  15. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/SOURCES.txt +0 -0
  16. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/dependency_links.txt +0 -0
  17. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/entry_points.txt +0 -0
  18. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/requires.txt +0 -0
  19. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/src/audio_scribe.egg-info/top_level.txt +0 -0
  20. {audio_scribe-0.1.2 → audio_scribe-0.1.3}/tests/test_config.py +0 -0
  21. {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.2
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/badge/License-Apache%202.0-blue.svg)](LICENSE)
52
- ![Coverage](https://img.shields.io/badge/coverage-94.3%25-brightgreen)
53
- [![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main)
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/badge/License-Apache%202.0-blue.svg)](LICENSE)
6
- ![Coverage](https://img.shields.io/badge/coverage-94.3%25-brightgreen)
7
- [![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main)
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.2",
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.",
@@ -11,7 +11,7 @@ from .config import TranscriptionConfig
11
11
  from .auth import TokenManager
12
12
  from .utils import DependencyManager, complete_path
13
13
 
14
- __version__ = "0.1.2"
14
+ __version__ = "0.1.3"
15
15
 
16
16
  __all__ = [
17
17
  "main",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: audio_scribe
3
- Version: 0.1.2
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/badge/License-Apache%202.0-blue.svg)](LICENSE)
52
- ![Coverage](https://img.shields.io/badge/coverage-94.3%25-brightgreen)
53
- [![Pipeline Status](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/badges/main/pipeline.svg)](https://gitlab.genomicops.cloud/innovation-hub/audio-scribe/-/commits/main)
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