|
15 | 15 | """ |
16 | 16 |
|
17 | 17 | import logging |
| 18 | +import time |
18 | 19 | from enum import Enum |
19 | 20 | from typing import Any, ClassVar |
20 | 21 |
|
@@ -412,15 +413,7 @@ async def _process_podcast_generation( |
412 | 413 | audio_stored = True # Mark audio as stored for cleanup if needed |
413 | 414 |
|
414 | 415 | # Step 6: Extract and serialize chapters |
415 | | - chapters_dict = [ |
416 | | - { |
417 | | - "title": chapter.title, |
418 | | - "start_time": chapter.start_time, |
419 | | - "end_time": chapter.end_time, |
420 | | - "word_count": chapter.word_count, |
421 | | - } |
422 | | - for chapter in podcast_script.chapters |
423 | | - ] |
| 416 | + chapters_dict = self._serialize_chapters(podcast_script) |
424 | 417 |
|
425 | 418 | # Step 7: Mark complete (100%) |
426 | 419 | self.repository.mark_completed( |
@@ -744,15 +737,22 @@ async def _generate_script(self, podcast_input: PodcastGenerationInput, rag_resu |
744 | 737 | # Initialize enhanced parser for quality validation |
745 | 738 | enhanced_parser = EnhancedScriptParser(average_wpm=150) |
746 | 739 |
|
747 | | - # Retry configuration |
748 | | - max_retries = 3 |
| 740 | + # Retry configuration (optimized for cost and latency) |
| 741 | + max_retries = 2 # Reduced from 3 to 2 (saves ~30s latency, $0.01-0.05 cost) |
749 | 742 | min_quality_score = 0.6 |
| 743 | + base_delay = 1.0 # Base delay for exponential backoff (seconds) |
750 | 744 |
|
751 | 745 | best_script = None |
752 | 746 | best_quality = 0.0 |
753 | 747 |
|
754 | 748 | for attempt in range(max_retries): |
755 | 749 | try: |
| 750 | + # Add exponential backoff between retries (2^attempt * base_delay) |
| 751 | + if attempt > 0: |
| 752 | + delay = base_delay * (2**attempt) |
| 753 | + logger.info("Retry attempt %d: waiting %.1fs before retry", attempt + 1, delay) |
| 754 | + time.sleep(delay) |
| 755 | + |
756 | 756 | script_text = llm_provider.generate_text( |
757 | 757 | user_id=user_id, |
758 | 758 | prompt="", # Empty - template contains full prompt |
@@ -807,6 +807,10 @@ async def _generate_script(self, podcast_input: PodcastGenerationInput, rag_resu |
807 | 807 | logger.error("Error generating script on attempt %d: %s", attempt + 1, e) |
808 | 808 | if attempt == max_retries - 1: |
809 | 809 | raise |
| 810 | + # Add exponential backoff on errors as well |
| 811 | + delay = base_delay * (2 ** (attempt + 1)) |
| 812 | + logger.info("Error recovery: waiting %.1fs before retry", delay) |
| 813 | + time.sleep(delay) |
810 | 814 |
|
811 | 815 | # If we exhausted retries, return best script with warning |
812 | 816 | if best_script: |
@@ -1177,6 +1181,30 @@ async def _update_progress( |
1177 | 1181 | status=status, |
1178 | 1182 | ) |
1179 | 1183 |
|
| 1184 | + def _serialize_chapters(self, podcast_script: PodcastScriptOutput) -> list[dict[str, Any]]: |
| 1185 | + """ |
| 1186 | + Serialize podcast chapters from PodcastScriptOutput to dictionary format. |
| 1187 | +
|
| 1188 | + Args: |
| 1189 | + podcast_script: Parsed podcast script with chapters |
| 1190 | +
|
| 1191 | + Returns: |
| 1192 | + List of chapter dictionaries with title, timestamps, and word count. |
| 1193 | + Returns empty list if chapters is None or empty. |
| 1194 | + """ |
| 1195 | + if not podcast_script.chapters: |
| 1196 | + return [] |
| 1197 | + |
| 1198 | + return [ |
| 1199 | + { |
| 1200 | + "title": chapter.title, |
| 1201 | + "start_time": chapter.start_time, |
| 1202 | + "end_time": chapter.end_time, |
| 1203 | + "word_count": chapter.word_count, |
| 1204 | + } |
| 1205 | + for chapter in podcast_script.chapters |
| 1206 | + ] |
| 1207 | + |
1180 | 1208 | async def get_podcast(self, podcast_id: UUID4, user_id: UUID4) -> PodcastGenerationOutput: |
1181 | 1209 | """ |
1182 | 1210 | Get podcast by ID with access control. |
@@ -1561,15 +1589,7 @@ async def _process_audio_from_script( |
1561 | 1589 | ) |
1562 | 1590 |
|
1563 | 1591 | # Step 5: Extract and serialize chapters |
1564 | | - chapters_dict = [ |
1565 | | - { |
1566 | | - "title": chapter.title, |
1567 | | - "start_time": chapter.start_time, |
1568 | | - "end_time": chapter.end_time, |
1569 | | - "word_count": chapter.word_count, |
1570 | | - } |
1571 | | - for chapter in podcast_script.chapters |
1572 | | - ] |
| 1592 | + chapters_dict = self._serialize_chapters(podcast_script) |
1573 | 1593 |
|
1574 | 1594 | # Step 6: Mark completed |
1575 | 1595 | self.repository.mark_completed( |
|
0 commit comments