TheArtOfStorytelling / Version2.md
awacke1's picture
Create Version2.md
51269cc verified

A newer version of the Streamlit SDK is available: 1.46.1

Upgrade

import streamlit as st import random import re from gtts import gTTS from PIL import Image, ImageDraw, ImageFont import io import base64

Default word lists for storytelling classes

default_word_lists = { "Location": ["quiet town", "small village", "city", "forest", "mountain"], "Actions": ["walking", "pedaling", "running", "dancing", "exploring"], "Thoughts": ["chasing shadows", "what if", "brilliance of years", "echoes", "secrets"], "Emotions": ["joy", "pain", "trembling smile", "storm", "silent art"], "Dialogue": [""Keep moving, dare to feel;"", ""Am I chasing shadows?"", ""The dawn awaits!"", ""I love you."", ""Letโ€™s go!""] }

Suit properties for narrative flavor

suit_properties = { "Hearts": "emotional or romantic", "Diamonds": "wealthy or luxurious", "Clubs": "conflict or struggle", "Spades": "mysterious or dangerous" }

Sentence templates for story generation

sentence_templates = { "Location": "The story unfolded in a {property} {word}.", "Actions": "Suddenly, a {property} {word} changed everything.", "Thoughts": "A {property} thought, '{word}', crossed their mind.", "Emotions": "A {property} wave of {word} surged through them.", "Dialogue": "Someone spoke with a {property} tone: {word}" }

Pure Python function to augment word lists from user input

def augment_word_lists(user_input): augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()}

# Split input into words
words = user_input.lower().split()

# Simple heuristic lists for categorization
location_keywords = ["town", "village", "city", "forest", "mountain", "place", "land"]
action_keywords = ["walk", "run", "dance", "pedal", "explore", "move", "jump"]
emotion_keywords = ["joy", "pain", "smile", "storm", "fear", "love", "anger"]

# Extract dialogues with regex
dialogues = re.findall(r'"[^"]*"', user_input)
augmented_lists["Dialogue"].extend(dialogues)

# Categorize words
for word in words:
    if any(keyword in word for keyword in location_keywords):
        augmented_lists["Location"].append(word)
    elif any(keyword in word for keyword in action_keywords):
        augmented_lists["Actions"].append(word)
    elif any(keyword in word for keyword in emotion_keywords):
        augmented_lists["Emotions"].append(word)
    elif "?" in word or "what" in word or "why" in word:  # Simple thought detection
        augmented_lists["Thoughts"].append(word)

# Remove duplicates
for key in augmented_lists:
    augmented_lists[key] = list(set(augmented_lists[key]))

return augmented_lists

Create a 52-card deck

def create_deck(): suits = ["Hearts", "Diamonds", "Clubs", "Spades"] ranks = list(range(1, 14)) deck = [(suit, rank) for suit in suits for rank in ranks] random.shuffle(deck) return deck

Assign cards to classes

def assign_card_to_class(card_index): if 0 <= card_index < 10: return "Location" elif 10 <= card_index < 20: return "Actions" elif 20 <= card_index < 30: return "Thoughts" elif 30 <= card_index < 40: return "Emotions" else: return "Dialogue"

Generate card image

def generate_card_image(suit, rank, story_class, word, property): img = Image.new("RGB", (200, 300), color="white") draw = ImageDraw.Draw(img) font = ImageFont.load_default()

draw.text((10, 10), f"{rank} of {suit}", fill="black", font=font)
draw.text((10, 50), f"Class: {story_class}", fill="black", font=font)
draw.text((10, 90), f"Word: {word}", fill="black", font=font)
draw.text((10, 130), f"Property: {property}", fill="black", font=font)

buffer = io.BytesIO()
img.save(buffer, format="PNG")
return buffer.getvalue()

Generate story sentence

def generate_story_sentence(story_class, word, property): return sentence_templates[story_class].format(word=word, property=property)

Generate song lyrics

def generate_song_lyrics(story_text): words = story_text.split() key_elements = [word for word in words if len(word) > 3][:12] # Simple filter for ~60 seconds lyrics = "\n".join([f"{key_elements[i]} {key_elements[i+1]}" for i in range(0, len(key_elements)-1, 2)]) return lyrics

Main app

def main(): st.set_page_config(page_title="StoryForge: The Game", page_icon="๐ŸŽด", layout="wide") st.title("๐ŸŽด StoryForge: A Storytelling Adventure ๐ŸŽด")

# User input
st.markdown("## ๐Ÿ“ Your Story Seed")
user_input = st.text_area("Paste your story inspiration here:", height=200)

# Session state initialization
if "augmented_lists" not in st.session_state:
    st.session_state.augmented_lists = default_word_lists
if "deck" not in st.session_state:
    st.session_state.deck = create_deck()
if "story" not in st.session_state:
    st.session_state.story = []
if "drawn_cards" not in st.session_state:
    st.session_state.drawn_cards = 0

# Process input
if st.button("Start Game"):
    if user_input:
        st.session_state.augmented_lists = augment_word_lists(user_input)
        st.session_state.deck = create_deck()
        st.session_state.story = []
        st.session_state.drawn_cards = 0
        st.success("Game started! Draw your first card.")

# Draw card and story display
col1, col2 = st.columns([1, 3])
with col1:
    if st.button("Draw Card") and st.session_state.drawn_cards < 52:
        card_index = st.session_state.drawn_cards
        suit, rank = st.session_state.deck[card_index]
        story_class = assign_card_to_class(card_index)
        word = random.choice(st.session_state.augmented_lists[story_class])
        property = suit_properties[suit]
        
        card_image = generate_card_image(suit, rank, story_class, word, property)
        st.image(card_image, caption=f"Card {card_index + 1}")
        
        sentence = generate_story_sentence(story_class, word, property)
        st.session_state.story.append(sentence)
        st.session_state.drawn_cards += 1

with col2:
    st.markdown("### ๐Ÿ“œ Your Story Unfolds")
    if st.session_state.story:
        st.write("\n".join(st.session_state.story))

# Song generation
if st.session_state.drawn_cards == 52:
    full_story = "\n".join(st.session_state.story)
    st.markdown("### ๐ŸŽต Story Song")
    lyrics = generate_song_lyrics(full_story)
    st.write(lyrics)
    
    tts = gTTS(text=lyrics, lang="en")
    audio_file = "story_song.mp3"
    tts.save(audio_file)
    st.audio(audio_file, format="audio/mp3")

# Enhanced UI with HTML/CSS
st.markdown("""
    ## ๐ŸŽฎ Game Board
    <div style="background-color: #f0f0f0; padding: 20px; border-radius: 10px; text-align: center;">
        <h3 style="color: #333;">Draw cards to weave your epic tale!</h3>
        <button style="background-color: #ff9900; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;"
                onmouseover="this.style.backgroundColor='#cc7700'" 
                onmouseout="this.style.backgroundColor='#ff9900'">
            Hover for a surprise!
        </button>
    </div>
""", unsafe_allow_html=True)

# Star layout
st.markdown("## โญ Five Pillars of Storytelling โญ")
star_html = """
<div style="position: relative; width: 400px; height: 400px; margin: auto; border: 1px dashed #aaa; border-radius: 50%;">
    <div style="position: absolute; top: 50px; left: 200px; transform: translate(-50%, -50%); text-align: center;">
        <div style="font-size: 2em;">๐Ÿ </div><div><b>Location</b></div>
    </div>
    <div style="position: absolute; top: 154px; left: 57px; transform: translate(-50%, -50%); text-align: center;">
        <div style="font-size: 2em;">๐Ÿƒ</div><div><b>Actions</b></div>
    </div>
    <div style="position: absolute; top: 321px; left: 112px; transform: translate(-50%, -50%); text-align: center;">
        <div style="font-size: 2em;">๐Ÿง </div><div><b>Thoughts</b></div>
    </div>
    <div style="position: absolute; top: 321px; left: 288px; transform: translate(-50%, -50%); text-align: center;">
        <div style="font-size: 2em;">๐Ÿ˜ฒ</div><div><b>Emotions</b></div>
    </div>
    <div style="position: absolute; top: 154px; left: 343px; transform: translate(-50%, -50%); text-align: center;">
        <div style="font-size: 2em;">๐Ÿ’ฌ</div><div><b>Dialogue</b></div>
    </div>
</div>
"""
st.markdown(star_html, unsafe_allow_html=True)

if name == "main": main()