Zoe09 Claude Sonnet 4.6 commited on
Commit
c0371e0
·
1 Parent(s): 81c371a

Load book list dynamically from stories/ folder

Browse files

- Replace hardcoded mock_books with load_books_from_stories()
- Title from filename (underscores → spaces), synopsis from first 3 lines of txt
- audio_path defaults to None (replaced by TTS at runtime), fallback to willow.wav for UI
- Rotate cover images across 10 books

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +53 -77
app.py CHANGED
@@ -65,79 +65,54 @@ for key, (path, dur, mel) in create_sound_library.items():
65
  if not os.path.exists(path):
66
  generate_chimes_wav(path, duration=dur, melody_type=mel)
67
 
68
- # Initial dataset of audiobooks
69
- mock_books = [
70
- {
71
- "id": "1",
72
- "title": "The Enchanted Willow",
73
- "author": "Elena S. Thorne",
74
- "cover_url": "https://images.unsplash.com/photo-1544947950-fa07a98d237f?auto=format&fit=crop&q=80&w=400",
75
- "voice_name": "Mom's Voice",
76
- "duration": 1200,
77
- "elapsed_time": 456,
78
- "synopsis": "Deep within the heart of Whispering Woods stands an ancient willow tree, rumored to hold the forgotten memories of the valley. When a young cartographer is sent to map the region, she starts hearing a gentle, familiar voice whispering from the rustling emerald leaves.",
79
- "category": "Fantasy",
80
- "is_cloned": True,
81
- "percentage": 38,
82
- "audio_path": "sample_sounds/willow.wav"
83
- },
84
- {
85
- "id": "2",
86
- "title": "The Clockwork Sky",
87
- "author": "Arthur Pendelton",
88
- "cover_url": "https://images.unsplash.com/photo-1512820790803-83ca734da794?auto=format&fit=crop&q=80&w=400",
89
- "voice_name": "Folk Storyteller",
90
- "duration": 1800,
91
- "elapsed_time": 0,
92
- "synopsis": "In a world where the heavens are driven by complex brass gears and clockwork stars, a young apprentice discovers an unaccounted gear grinding in the midnight sky—a secret that the High Astrologers have hidden for a millennium.",
93
- "category": "Sci-Fi & Steampunk",
94
- "is_cloned": False,
95
- "percentage": 0,
96
- "audio_path": "sample_sounds/sky.wav"
97
- },
98
- {
99
- "id": "3",
100
- "title": "Echoes of the Deep",
101
- "author": "Mariana Vance",
102
- "cover_url": "https://images.unsplash.com/photo-1476275466078-4007374efbbe?auto=format&fit=crop&q=80&w=400",
103
- "voice_name": "Grandpa Joseph",
104
- "duration": 2400,
105
- "elapsed_time": 1200,
106
- "synopsis": "A quiet oceanographer working in a remote marine sanctuary begins to trace an unusual, rhythmic hum coming from the Marianas Trench. The signal grows stronger, mimicking a lullaby his grandfather used to whistle.",
107
- "category": "Adventure",
108
- "is_cloned": True,
109
- "percentage": 50,
110
- "audio_path": "sample_sounds/deep.wav"
111
- },
112
- {
113
- "id": "4",
114
- "title": "The Midnight Baker",
115
- "author": "Clara Dupont",
116
- "cover_url": "https://images.unsplash.com/photo-1456513080510-7bf3a84b82f8?auto=format&fit=crop&q=80&w=400",
117
- "voice_name": "Mom's Voice",
118
- "duration": 980,
119
- "elapsed_time": 980,
120
- "synopsis": "Every night at midnight, Clara bakes bread that infuses the sleeping town with warmth. Customers don’t buy her pastries to satisfy hunger; they eat them to relive the comforting memories of childhood summers.",
121
- "category": "Slice of Life",
122
- "is_cloned": True,
123
- "percentage": 100,
124
- "audio_path": "sample_sounds/baker.wav"
125
- },
126
- {
127
- "id": "5",
128
- "title": "Letters from Paris",
129
- "author": "Julian Mercer",
130
- "cover_url": "https://images.unsplash.com/photo-1492052722242-2554d0e99e3a?auto=format&fit=crop&q=80&w=400",
131
- "voice_name": "Grandpa Joseph",
132
- "duration": 1560,
133
- "elapsed_time": 0,
134
- "synopsis": "A bundle of yellowed, ribbon-bound letters hidden inside an attic chest on Rue de l’Odeon unravels a heartbreaking secret of courage and hidden artwork dating back to the winter of 1944.",
135
- "category": "Historical Fiction",
136
- "is_cloned": True,
137
- "percentage": 0,
138
- "audio_path": "sample_sounds/letters.wav"
139
- }
140
- ]
141
 
142
  mock_voices = [
143
  {
@@ -796,13 +771,13 @@ with gr.Blocks(css=css_code, title="VoiceBook Gradio Hub") as demo:
796
  </div>
797
  """
798
 
799
- # update player tabs active
800
  return (
801
  player_html_markup,
802
- selected["audio_path"],
803
  selected["synopsis"],
804
  selected["category"],
805
- gr.Tabs(selected="player") # Select player tab
806
  )
807
 
808
  mount_play_btn.click(
@@ -830,9 +805,10 @@ with gr.Blocks(css=css_code, title="VoiceBook Gradio Hub") as demo:
830
  <span style="font-size: 11px; color: #94a3b8; font-family: monospace;">READY</span>
831
  </div>
832
  """
 
833
  return (
834
  player_html_markup,
835
- selected["audio_path"],
836
  selected["synopsis"],
837
  selected["category"],
838
  status_html,
 
65
  if not os.path.exists(path):
66
  generate_chimes_wav(path, duration=dur, melody_type=mel)
67
 
68
+ def load_books_from_stories(stories_dir="stories"):
69
+ books = []
70
+ story_files = sorted(
71
+ f for f in os.listdir(stories_dir) if f.endswith(".txt")
72
+ ) if os.path.isdir(stories_dir) else []
73
+
74
+ cover_urls = [
75
+ "https://images.unsplash.com/photo-1544947950-fa07a98d237f?auto=format&fit=crop&q=80&w=400",
76
+ "https://images.unsplash.com/photo-1512820790803-83ca734da794?auto=format&fit=crop&q=80&w=400",
77
+ "https://images.unsplash.com/photo-1476275466078-4007374efbbe?auto=format&fit=crop&q=80&w=400",
78
+ "https://images.unsplash.com/photo-1456513080510-7bf3a84b82f8?auto=format&fit=crop&q=80&w=400",
79
+ "https://images.unsplash.com/photo-1492052722242-2554d0e99e3a?auto=format&fit=crop&q=80&w=400",
80
+ "https://images.unsplash.com/photo-1474932430478-367dbb6832c1?auto=format&fit=crop&q=80&w=400",
81
+ "https://images.unsplash.com/photo-1456513080510-7bf3a84b82f8?auto=format&fit=crop&q=80&w=400",
82
+ "https://images.unsplash.com/photo-1495640388908-05fa85288e61?auto=format&fit=crop&q=80&w=400",
83
+ "https://images.unsplash.com/photo-1476275466078-4007374efbbe?auto=format&fit=crop&q=80&w=400",
84
+ "https://images.unsplash.com/photo-1512820790803-83ca734da794?auto=format&fit=crop&q=80&w=400",
85
+ ]
86
+
87
+ for i, filename in enumerate(story_files):
88
+ title = filename.replace(".txt", "").replace("_", " ")
89
+ # Read first non-empty line as synopsis opener
90
+ synopsis = ""
91
+ try:
92
+ with open(os.path.join(stories_dir, filename), encoding="utf-8") as f:
93
+ lines = [l.strip() for l in f.readlines() if l.strip()]
94
+ synopsis = " ".join(lines[1:4]) if len(lines) > 1 else lines[0] if lines else ""
95
+ except Exception:
96
+ pass
97
+
98
+ books.append({
99
+ "id": str(i + 1),
100
+ "title": title,
101
+ "author": "Public Domain",
102
+ "cover_url": cover_urls[i % len(cover_urls)],
103
+ "voice_name": "Mom’s Voice",
104
+ "duration": 0,
105
+ "elapsed_time": 0,
106
+ "synopsis": synopsis,
107
+ "category": "Children’s Story",
108
+ "is_cloned": False,
109
+ "percentage": 0,
110
+ "audio_path": None, # replaced by TTS at runtime
111
+ "story_path": os.path.join(stories_dir, filename),
112
+ })
113
+ return books
114
+
115
+ mock_books = load_books_from_stories()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  mock_voices = [
118
  {
 
771
  </div>
772
  """
773
 
774
+ audio = selected["audio_path"] or "sample_sounds/willow.wav"
775
  return (
776
  player_html_markup,
777
+ audio,
778
  selected["synopsis"],
779
  selected["category"],
780
+ gr.Tabs(selected="player")
781
  )
782
 
783
  mount_play_btn.click(
 
805
  <span style="font-size: 11px; color: #94a3b8; font-family: monospace;">READY</span>
806
  </div>
807
  """
808
+ audio = selected["audio_path"] or "sample_sounds/willow.wav"
809
  return (
810
  player_html_markup,
811
+ audio,
812
  selected["synopsis"],
813
  selected["category"],
814
  status_html,