Skip to content

Commit 19a3c44

Browse files
committed
Expanding path for ffpmeg
1 parent 30f8b62 commit 19a3c44

File tree

2 files changed

+44
-29
lines changed

2 files changed

+44
-29
lines changed

services/transcription.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ def compress_audio_for_whisper(audio_path: str) -> str:
3636
Raises:
3737
Exception: If compression fails
3838
"""
39+
# Expand ~ in path for ffmpeg (ffmpeg doesn't handle ~ paths)
40+
expanded_audio_path = str(Path(audio_path).expanduser().resolve())
41+
3942
logger.info(
40-
f"Compressing audio file {audio_path} for Whisper (1.5x speed, saves API costs)"
43+
f"Compressing audio file {expanded_audio_path} for Whisper (1.5x speed, saves API costs)"
4144
)
4245

4346
# Create temporary file for compressed audio
@@ -51,7 +54,7 @@ def compress_audio_for_whisper(audio_path: str) -> str:
5154
compress_cmd = [
5255
"ffmpeg",
5356
"-i",
54-
audio_path,
57+
expanded_audio_path,
5558
"-filter:a",
5659
"atempo=1.5", # Speed up by 1.5x (33% file size reduction)
5760
"-map",
@@ -80,7 +83,7 @@ def compress_audio_for_whisper(audio_path: str) -> str:
8083

8184
temp_path_path = Path(temp_path)
8285
compressed_size = temp_path_path.stat().st_size
83-
original_size = Path(audio_path).expanduser().resolve().stat().st_size
86+
original_size = Path(expanded_audio_path).stat().st_size
8487

8588
logger.info(
8689
f"Compressed audio from {original_size / 1024 / 1024:.2f}MB "
@@ -218,19 +221,22 @@ def transcribe_audio_gemini(audio_path: str, retries: int = 3) -> str:
218221
if not config.gemini_api_key:
219222
raise ValueError("Gemini API key not configured")
220223

224+
# Expand ~ in path (Python's open() doesn't handle ~ paths)
225+
expanded_audio_path = str(Path(audio_path).expanduser().resolve())
226+
221227
last_error = None
222228

223229
for attempt in range(retries):
224230
try:
225231
logger.info(
226-
f"Transcribing audio file with Gemini: {audio_path} (attempt {attempt + 1}/{retries})"
232+
f"Transcribing audio file with Gemini: {expanded_audio_path} (attempt {attempt + 1}/{retries})"
227233
)
228234

229235
# Create Gemini client
230236
client = genai.Client(api_key=config.gemini_api_key)
231237

232238
# Upload the audio file
233-
with open(audio_path, "rb") as audio_file:
239+
with open(expanded_audio_path, "rb") as audio_file:
234240
audio_data = audio_file.read()
235241

236242
# Use Gemini to transcribe

tests/services/test_transcription.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,27 @@ def test_compress_audio_success(
3030
compressed_stat.st_size = 3 * 1024 * 1024
3131
mock_temp_path_instance.stat.return_value = compressed_stat
3232

33-
# Second call: Path(audio_path).expanduser().resolve()
34-
original_stat = Mock()
35-
original_stat.st_size = 10 * 1024 * 1024
36-
37-
# Create the chain: instance.expanduser().resolve().stat() returns original_stat
38-
mock_resolved_instance = Mock()
39-
mock_resolved_instance.stat.return_value = original_stat
40-
33+
# Second call: Path(audio_path).expanduser().resolve() - for path expansion
4134
mock_expanded_instance = Mock()
42-
mock_expanded_instance.resolve.return_value = mock_resolved_instance
35+
mock_expanded_instance.resolve.return_value = Mock(
36+
__str__=lambda x: "/expanded/path/audio.mp3"
37+
)
4338

4439
mock_audio_path_instance = Mock()
4540
mock_audio_path_instance.expanduser.return_value = mock_expanded_instance
4641

47-
mock_path.side_effect = [mock_temp_path_instance, mock_audio_path_instance]
42+
# Third call: Path(expanded_audio_path).stat() - for original file size
43+
original_stat = Mock()
44+
original_stat.st_size = 10 * 1024 * 1024
45+
46+
mock_original_path_instance = Mock()
47+
mock_original_path_instance.stat.return_value = original_stat
48+
49+
mock_path.side_effect = [
50+
mock_audio_path_instance,
51+
mock_temp_path_instance,
52+
mock_original_path_instance,
53+
]
4854

4955
# Mock file sizes
5056
mock_getsize.side_effect = [10 * 1024 * 1024, 3 * 1024 * 1024] # 10MB -> 3MB
@@ -110,34 +116,37 @@ def test_compress_audio_still_too_large(
110116
"""Test compression when result is still too large."""
111117
mock_mkstemp.return_value = (123, "/tmp/test.mp3")
112118

113-
# Mock Path with .expanduser().resolve() chain
114-
# First call: Path(temp_path) - no expanduser/resolve
119+
# Mock Path calls in order:
120+
# 1. Path(audio_path).expanduser().resolve() - for path expansion
121+
mock_expanded_instance = Mock()
122+
mock_expanded_instance.resolve.return_value = Mock(
123+
__str__=lambda x: "/expanded/path/audio.mp3"
124+
)
125+
126+
mock_audio_path_instance = Mock()
127+
mock_audio_path_instance.expanduser.return_value = mock_expanded_instance
128+
129+
# 2. Path(temp_path).stat() - for compressed file size
115130
mock_temp_path_instance = Mock()
116131
compressed_stat = Mock()
117132
compressed_stat.st_size = 30 * 1024 * 1024 # 30MB (over 25MB limit)
118133
mock_temp_path_instance.stat.return_value = compressed_stat
119134

120-
# Second call: Path(audio_path).expanduser().resolve()
135+
# 3. Path(expanded_audio_path).stat() - for original file size
121136
original_stat = Mock()
122137
original_stat.st_size = 50 * 1024 * 1024 # 50MB original
123138

124-
# Create the chain: instance.expanduser().resolve().stat() returns original_stat
125-
mock_resolved_instance = Mock()
126-
mock_resolved_instance.stat.return_value = original_stat
127-
128-
mock_expanded_instance = Mock()
129-
mock_expanded_instance.resolve.return_value = mock_resolved_instance
130-
131-
mock_audio_path_instance = Mock()
132-
mock_audio_path_instance.expanduser.return_value = mock_expanded_instance
139+
mock_original_path_instance = Mock()
140+
mock_original_path_instance.stat.return_value = original_stat
133141

134-
# Need a third instance for cleanup in except block
142+
# 4. Path(temp_path) - for cleanup in except block
135143
mock_cleanup_path_instance = Mock()
136144
mock_cleanup_path_instance.exists.return_value = True
137145

138146
mock_path.side_effect = [
139-
mock_temp_path_instance,
140147
mock_audio_path_instance,
148+
mock_temp_path_instance,
149+
mock_original_path_instance,
141150
mock_cleanup_path_instance,
142151
]
143152
mock_exists.return_value = True

0 commit comments

Comments
 (0)