awacke1 commited on
Commit
63cd97c
ยท
verified ยท
1 Parent(s): 003b1ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -104
app.py CHANGED
@@ -15,11 +15,7 @@ from gradio_client import Client
15
 
16
  warnings.filterwarnings('ignore')
17
 
18
- # Initialize constants
19
- PAGE_SIZE = 10
20
- FILE_DIR_PATH = "gallery"
21
-
22
- # Initialize story starters
23
  STORY_STARTERS = [
24
  ['Adventure', 'In a hidden temple deep in the Amazon...'],
25
  ['Mystery', 'The detective found an unusual note...'],
@@ -43,25 +39,23 @@ def init_client():
43
  return arxiv_client
44
 
45
  def save_story(story, audio_path):
46
- """Save story and audio to gallery"""
47
  try:
48
  # Create gallery directory if it doesn't exist
49
- gallery_dir = Path(FILE_DIR_PATH)
50
  gallery_dir.mkdir(exist_ok=True)
51
 
52
- # Generate timestamp for unique filename
53
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
54
-
55
- # Get first line for title
56
  first_line = story.split('\n')[0].strip()
57
- safe_name = re.sub(r'[^\w\s-]', '', first_line)[:50]
58
 
59
  # Save story text as markdown
60
  story_path = gallery_dir / f"story_{timestamp}_{safe_name}.md"
61
  with open(story_path, "w") as f:
62
  f.write(f"# {first_line}\n\n{story}")
63
 
64
- # Copy audio file to gallery
65
  new_audio_path = None
66
  if audio_path:
67
  new_audio_path = gallery_dir / f"audio_{timestamp}_{safe_name}.mp3"
@@ -72,39 +66,43 @@ def save_story(story, audio_path):
72
  print(f"Error saving to gallery: {str(e)}")
73
  return None, None
74
 
75
- def list_all_outputs(generation_history):
76
- """Load all story generations for community view"""
77
  try:
78
- directory_path = FILE_DIR_PATH
79
- if not os.path.exists(directory_path):
80
- return "", gr.update(visible=True)
 
 
 
 
 
 
81
 
82
- # Get all matched pairs of story/audio files
83
- file_pairs = []
84
- for story_file in Path(directory_path).glob("story_*.md"):
85
- timestamp = story_file.stem.split('_')[1]
86
  audio_pattern = f"audio_{timestamp}_*.mp3"
87
- audio_files = list(Path(directory_path).glob(audio_pattern))
 
88
 
89
- if audio_files: # Only include if we have both story and audio
90
- file_pairs.append((story_file, audio_files[0]))
91
-
92
- # Sort by modification time, newest first
93
- file_pairs.sort(key=lambda x: os.path.getmtime(x[0]), reverse=True)
94
-
95
- history_list = generation_history.split(',') if generation_history else []
96
- updated_files = [str(audio) for _, audio in file_pairs if str(audio) not in history_list]
97
- updated_history = updated_files + history_list
 
 
 
98
 
99
- return ','.join(updated_history), gr.update(visible=True)
100
  except Exception as e:
101
- print(f"Error loading community generations: {str(e)}")
102
- return "", gr.update(visible=True)
103
-
104
- def increase_list_size(list_size):
105
- """Increase the number of visible community generations"""
106
- return list_size + PAGE_SIZE
107
 
 
108
  def generate_story(prompt, model_choice):
109
  """Generate story using specified model"""
110
  try:
@@ -140,7 +138,7 @@ def process_story_and_audio(prompt, model_choice):
140
  # Generate story
141
  story = generate_story(prompt, model_choice)
142
  if isinstance(story, str) and story.startswith("Error"):
143
- return story, None
144
 
145
  # Generate audio
146
  audio_path = asyncio.run(generate_speech(story))
@@ -148,41 +146,29 @@ def process_story_and_audio(prompt, model_choice):
148
  # Save to gallery
149
  story_path, saved_audio_path = save_story(story, audio_path)
150
 
151
- return story, audio_path
152
  except Exception as e:
153
- return f"Error: {str(e)}", None
154
 
155
- # Add CSS for community generations
156
- css = '''
157
- #live_gen:before {
158
- content: '';
159
- animation: svelte-z7cif2-pulseStart 1s cubic-bezier(.4,0,.6,1), svelte-z7cif2-pulse 2s cubic-bezier(.4,0,.6,1) 1s infinite;
160
- border: 2px solid var(--color-accent);
161
- background: transparent;
162
- z-index: var(--layer-1);
163
- pointer-events: none;
164
- position: absolute;
165
- height: 100%;
166
- width: 100%;
167
- border-radius: 7px;
168
- }
169
- #live_gen_items{
170
- max-height: 570px;
171
- overflow-y: scroll;
172
- }
173
- '''
174
 
175
- # Create the Gradio interface
176
- with gr.Blocks(title="AI Story Generator", css=css) as demo:
177
  gr.Markdown("""
178
  # ๐ŸŽญ AI Story Generator & Narrator
179
  Generate creative stories, listen to them, and build your gallery!
180
  """)
181
 
182
- # Add hidden state for community generations
183
- generation_history = gr.Textbox(visible=False)
184
- list_size = gr.Number(value=PAGE_SIZE, visible=False)
185
-
186
  with gr.Row():
187
  with gr.Column(scale=3):
188
  with gr.Row():
@@ -216,7 +202,7 @@ with gr.Blocks(title="AI Story Generator", css=css) as demo:
216
  type="filepath"
217
  )
218
 
219
- # Sidebar with Story Starters and Community Generations
220
  with gr.Column(scale=1):
221
  gr.Markdown("### ๐Ÿ“š Story Starters")
222
  story_starters = gr.Dataframe(
@@ -225,40 +211,12 @@ with gr.Blocks(title="AI Story Generator", css=css) as demo:
225
  interactive=False
226
  )
227
 
228
- # Community Generations section
229
- with gr.Column(elem_id="live_gen") as community_list:
230
- gr.Markdown("### ๐ŸŽฌ Community Stories")
231
- with gr.Column(elem_id="live_gen_items"):
232
- @gr.render(inputs=[generation_history, list_size])
233
- def show_output_list(generation_history, list_size):
234
- history_list = generation_history.split(',') if generation_history else []
235
- history_list_latest = history_list[:list_size]
236
-
237
- for audio_path in history_list_latest:
238
- if not audio_path or not os.path.exists(audio_path):
239
- continue
240
-
241
- try:
242
- # Get corresponding story file
243
- story_path = audio_path.replace('audio_', 'story_').replace('.mp3', '.md')
244
- if not os.path.exists(story_path):
245
- continue
246
-
247
- # Read story content
248
- with open(story_path, 'r') as file:
249
- story_content = file.read()
250
- # Extract title from markdown
251
- title = story_content.split('\n')[0].replace('# ', '')
252
-
253
- with gr.Group():
254
- gr.Markdown(value=f"### {title}")
255
- gr.Audio(value=audio_path)
256
- except Exception as e:
257
- print(f"Error showing generation: {str(e)}")
258
- continue
259
-
260
- load_more = gr.Button("Load More Stories")
261
- load_more.click(fn=increase_list_size, inputs=list_size, outputs=list_size)
262
 
263
  # Event handlers
264
  def update_prompt(evt: gr.SelectData):
@@ -269,11 +227,14 @@ with gr.Blocks(title="AI Story Generator", css=css) as demo:
269
  generate_btn.click(
270
  fn=process_story_and_audio,
271
  inputs=[prompt_input, model_choice],
272
- outputs=[story_output, audio_output]
273
  )
274
 
275
- # Auto-refresh for community generations
276
- demo.load(fn=list_all_outputs, inputs=generation_history, outputs=[generation_history, community_list], every=2)
 
 
 
277
 
278
  if __name__ == "__main__":
279
  demo.launch()
 
15
 
16
  warnings.filterwarnings('ignore')
17
 
18
+ # Initialize story starters with added comedy section
 
 
 
 
19
  STORY_STARTERS = [
20
  ['Adventure', 'In a hidden temple deep in the Amazon...'],
21
  ['Mystery', 'The detective found an unusual note...'],
 
39
  return arxiv_client
40
 
41
  def save_story(story, audio_path):
42
+ """Save story and audio to gallery with markdown formatting"""
43
  try:
44
  # Create gallery directory if it doesn't exist
45
+ gallery_dir = Path("gallery")
46
  gallery_dir.mkdir(exist_ok=True)
47
 
48
+ # Generate timestamp and sanitize first line for filename
49
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
 
 
50
  first_line = story.split('\n')[0].strip()
51
+ safe_name = re.sub(r'[^\w\s-]', '', first_line)[:50] # First 50 chars, sanitized
52
 
53
  # Save story text as markdown
54
  story_path = gallery_dir / f"story_{timestamp}_{safe_name}.md"
55
  with open(story_path, "w") as f:
56
  f.write(f"# {first_line}\n\n{story}")
57
 
58
+ # Copy audio file to gallery with matching name
59
  new_audio_path = None
60
  if audio_path:
61
  new_audio_path = gallery_dir / f"audio_{timestamp}_{safe_name}.mp3"
 
66
  print(f"Error saving to gallery: {str(e)}")
67
  return None, None
68
 
69
+ def load_gallery():
70
+ """Load all stories and audio from gallery with markdown support"""
71
  try:
72
+ gallery_dir = Path("gallery")
73
+ if not gallery_dir.exists():
74
+ return []
75
+
76
+ files = []
77
+ for story_file in sorted(gallery_dir.glob("story_*.md"), reverse=True):
78
+ # Extract timestamp and name from filename
79
+ parts = story_file.stem.split('_', 2)
80
+ timestamp = f"{parts[1]}"
81
 
82
+ # Find matching audio file
 
 
 
83
  audio_pattern = f"audio_{timestamp}_*.mp3"
84
+ audio_files = list(gallery_dir.glob(audio_pattern))
85
+ audio_file = audio_files[0] if audio_files else None
86
 
87
+ # Read story content and get preview
88
+ with open(story_file) as f:
89
+ content = f.read()
90
+ # Skip markdown header and get preview
91
+ preview = content.split('\n\n', 1)[1][:100] + "..."
92
+
93
+ files.append([
94
+ timestamp,
95
+ f"[{preview}]({str(story_file)})", # Markdown link to story
96
+ str(story_file),
97
+ str(audio_file) if audio_file else None
98
+ ])
99
 
100
+ return files
101
  except Exception as e:
102
+ print(f"Error loading gallery: {str(e)}")
103
+ return []
 
 
 
 
104
 
105
+ # Keep all other functions unchanged
106
  def generate_story(prompt, model_choice):
107
  """Generate story using specified model"""
108
  try:
 
138
  # Generate story
139
  story = generate_story(prompt, model_choice)
140
  if isinstance(story, str) and story.startswith("Error"):
141
+ return story, None, None
142
 
143
  # Generate audio
144
  audio_path = asyncio.run(generate_speech(story))
 
146
  # Save to gallery
147
  story_path, saved_audio_path = save_story(story, audio_path)
148
 
149
+ return story, audio_path, load_gallery()
150
  except Exception as e:
151
+ return f"Error: {str(e)}", None, None
152
 
153
+ def play_gallery_audio(evt: gr.SelectData, gallery_data):
154
+ """Play audio from gallery selection"""
155
+ try:
156
+ selected_row = gallery_data[evt.index[0]]
157
+ audio_path = selected_row[3] # Audio path is the fourth element
158
+ if audio_path and os.path.exists(audio_path):
159
+ return audio_path
160
+ return None
161
+ except Exception as e:
162
+ print(f"Error playing gallery audio: {str(e)}")
163
+ return None
 
 
 
 
 
 
 
 
164
 
165
+ # Create the Gradio interface (keep unchanged)
166
+ with gr.Blocks(title="AI Story Generator") as demo:
167
  gr.Markdown("""
168
  # ๐ŸŽญ AI Story Generator & Narrator
169
  Generate creative stories, listen to them, and build your gallery!
170
  """)
171
 
 
 
 
 
172
  with gr.Row():
173
  with gr.Column(scale=3):
174
  with gr.Row():
 
202
  type="filepath"
203
  )
204
 
205
+ # Sidebar with Story Starters and Gallery
206
  with gr.Column(scale=1):
207
  gr.Markdown("### ๐Ÿ“š Story Starters")
208
  story_starters = gr.Dataframe(
 
211
  interactive=False
212
  )
213
 
214
+ gr.Markdown("### ๐ŸŽฌ Gallery")
215
+ gallery = gr.Dataframe(
216
+ value=load_gallery(),
217
+ headers=["Timestamp", "Preview", "Story Path", "Audio Path"],
218
+ interactive=False
219
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
  # Event handlers
222
  def update_prompt(evt: gr.SelectData):
 
227
  generate_btn.click(
228
  fn=process_story_and_audio,
229
  inputs=[prompt_input, model_choice],
230
+ outputs=[story_output, audio_output, gallery]
231
  )
232
 
233
+ gallery.select(
234
+ fn=play_gallery_audio,
235
+ inputs=[gallery],
236
+ outputs=[audio_output]
237
+ )
238
 
239
  if __name__ == "__main__":
240
  demo.launch()