import gradio as gr import random from datetime import datetime import tempfile import os import edge_tts import asyncio import warnings import pytz import re import json import pandas as pd from pathlib import Path from gradio_client import Client warnings.filterwarnings('ignore') # Initialize story starters with added comedy section STORY_STARTERS = [ ['Adventure', 'In a hidden temple deep in the Amazon...'], ['Mystery', 'The detective found an unusual note...'], ['Romance', 'Two strangers meet on a rainy evening...'], ['Sci-Fi', 'The space station received an unexpected signal...'], ['Fantasy', 'A magical portal appeared in the garden...'], ['Comedy-Sitcom', 'The new roommate arrived with seven emotional support animals...'], ['Comedy-Workplace', 'The office printer started sending mysterious messages...'], ['Comedy-Family', 'Grandma decided to become a social media influencer...'], ['Comedy-Supernatural', 'The ghost haunting the house was absolutely terrible at scaring people...'], ['Comedy-Travel', 'The GPS insisted on giving directions in interpretive dance descriptions...'] ] # Initialize client outside of interface definition arxiv_client = None def init_client(): global arxiv_client if arxiv_client is None: arxiv_client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern") return arxiv_client def save_story(story, audio_path): """Save story and audio to gallery with markdown formatting""" try: # Create gallery directory if it doesn't exist gallery_dir = Path("gallery") gallery_dir.mkdir(exist_ok=True) # Generate timestamp and sanitize first line for filename timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") first_line = story.split('\n')[0].strip() safe_name = re.sub(r'[^\w\s-]', '', first_line)[:50] # First 50 chars, sanitized # Save story text as markdown story_path = gallery_dir / f"story_{timestamp}_{safe_name}.md" with open(story_path, "w") as f: f.write(f"# {first_line}\n\n{story}") # Copy audio file to gallery with matching name new_audio_path = None if audio_path: new_audio_path = gallery_dir / f"audio_{timestamp}_{safe_name}.mp3" os.system(f"cp {audio_path} {str(new_audio_path)}") return str(story_path), str(new_audio_path) if new_audio_path else None except Exception as e: print(f"Error saving to gallery: {str(e)}") return None, None def load_gallery(): """Load all stories and audio from gallery with markdown support""" try: gallery_dir = Path("gallery") if not gallery_dir.exists(): return [] files = [] for story_file in sorted(gallery_dir.glob("story_*.md"), reverse=True): # Extract timestamp and name from filename parts = story_file.stem.split('_', 2) timestamp = f"{parts[1]}" # Find matching audio file audio_pattern = f"audio_{timestamp}_*.mp3" audio_files = list(gallery_dir.glob(audio_pattern)) audio_file = audio_files[0] if audio_files else None # Read story content and get preview with open(story_file) as f: content = f.read() # Skip markdown header and get preview preview = content.split('\n\n', 1)[1][:100] + "..." files.append([ timestamp, f"[{preview}]({str(story_file)})", # Markdown link to story str(story_file), str(audio_file) if audio_file else None ]) return files except Exception as e: print(f"Error loading gallery: {str(e)}") return [] # Keep all other functions unchanged def generate_story(prompt, model_choice): """Generate story using specified model""" try: client = init_client() if client is None: return "Error: Story generation service is not available." result = client.predict( prompt=prompt, llm_model_picked=model_choice, stream_outputs=True, api_name="/ask_llm" ) return result except Exception as e: return f"Error generating story: {str(e)}" async def generate_speech(text, voice="en-US-AriaNeural"): """Generate speech from text""" try: communicate = edge_tts.Communicate(text, voice) with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file: tmp_path = tmp_file.name await communicate.save(tmp_path) return tmp_path except Exception as e: print(f"Error in text2speech: {str(e)}") return None def process_story_and_audio(prompt, model_choice): """Process story, generate audio, and save to gallery""" try: # Generate story story = generate_story(prompt, model_choice) if isinstance(story, str) and story.startswith("Error"): return story, None, None # Generate audio audio_path = asyncio.run(generate_speech(story)) # Save to gallery story_path, saved_audio_path = save_story(story, audio_path) return story, audio_path, load_gallery() except Exception as e: return f"Error: {str(e)}", None, None def play_gallery_audio(evt: gr.SelectData, gallery_data): """Play audio from gallery selection""" try: selected_row = gallery_data[evt.index[0]] audio_path = selected_row[3] # Audio path is the fourth element if audio_path and os.path.exists(audio_path): return audio_path return None except Exception as e: print(f"Error playing gallery audio: {str(e)}") return None # Create the Gradio interface (keep unchanged) with gr.Blocks(title="AI Story Generator") as demo: gr.Markdown(""" # 🎭 AI Story Generator & Narrator Generate creative stories, listen to them, and build your gallery! """) with gr.Row(): with gr.Column(scale=3): with gr.Row(): prompt_input = gr.Textbox( label="Story Concept", placeholder="Enter your story idea...", lines=3 ) with gr.Row(): model_choice = gr.Dropdown( label="Model", choices=[ "mistralai/Mixtral-8x7B-Instruct-v0.1", "mistralai/Mistral-7B-Instruct-v0.2" ], value="mistralai/Mixtral-8x7B-Instruct-v0.1" ) generate_btn = gr.Button("Generate Story") with gr.Row(): story_output = gr.Textbox( label="Generated Story", lines=10, interactive=False ) with gr.Row(): audio_output = gr.Audio( label="Story Narration", type="filepath" ) # Sidebar with Story Starters and Gallery with gr.Column(scale=1): gr.Markdown("### 📚 Story Starters") gr.Markdown("# 🎯 𝓜𝓲𝔁𝓽𝓻𝓪𝓵 𝓸𝓯 𝓔𝔁𝓹𝓮𝓻𝓽𝓼 ⚡") gr.Markdown("**Abstract**: https://arxiv.org/abs/2401.04088") gr.Markdown("# 📖 𝓬𝓼 𝓪𝓻𝓧𝓲𝓿: 𝟮𝟰𝟬𝟭.𝟬𝟰𝟬𝟴𝟴 💫") gr.Markdown("**arxiv**: https://arxiv.org/pdf/2401.04088") story_starters = gr.Dataframe( value=STORY_STARTERS, headers=["Category", "Starter"], interactive=False ) gr.Markdown("### 🎬 Gallery") gallery = gr.Dataframe( value=load_gallery(), headers=["Timestamp", "Preview", "Story Path", "Audio Path"], interactive=False ) # Event handlers def update_prompt(evt: gr.SelectData): return STORY_STARTERS[evt.index[0]][1] story_starters.select(update_prompt, None, prompt_input) generate_btn.click( fn=process_story_and_audio, inputs=[prompt_input, model_choice], outputs=[story_output, audio_output, gallery] ) gallery.select( fn=play_gallery_audio, inputs=[gallery], outputs=[audio_output] ) if __name__ == "__main__": demo.launch()