Spaces:
Sleeping
Sleeping
File size: 7,190 Bytes
1c26e4c e211a6f 1c26e4c e211a6f 1a70ad2 e211a6f 1a70ad2 e211a6f 1a70ad2 e211a6f 1a70ad2 e211a6f 1a70ad2 e211a6f 1c26e4c e211a6f 1c26e4c e211a6f 1c26e4c e211a6f 1c26e4c e211a6f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
import streamlit as st
import spacy
import random
import re
from gtts import gTTS
from PIL import Image, ImageDraw, ImageFont
import io
import numpy as np
import base64
# Load spaCy model for NLP
nlp = spacy.load("en_core_web_sm")
# Default word lists for storytelling classes
default_word_lists = {
"Characters": ["Hero", "Villain", "Protagonist", "Antagonist", "Wizard", "Knight"],
"Settings": ["Forest", "City", "Castle", "Beach", "Mountain", "Space"],
"Events": ["Adventure", "Romance", "Mystery", "Conflict", "Discovery", "Escape"],
"Objects": ["Sword", "Magic potion", "Treasure chest", "Book", "Ring", "Spaceship"],
"Dialogues": ["\"Hello, how are you?\"", "\"Let's go!\"", "\"Beware the danger!\"", "\"I love you.\""]
}
# 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 = {
"Characters": "There was a {word} who was {property}.",
"Settings": "The {word} was {property}, stretching far into the distance.",
"Events": "Then, a {property} {word} unfolded.",
"Objects": "A {property} {word} appeared before them.",
"Dialogues": "One of them said, {word}, with a {property} tone."
}
# Function to process user input and augment word lists
def augment_word_lists(user_input):
doc = nlp(user_input)
augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()} # Start with defaults
# Extract elements from user input
for ent in doc.ents:
if ent.label_ == "PERSON":
augmented_lists["Characters"].append(ent.text)
elif ent.label_ in ["GPE", "LOC"]:
augmented_lists["Settings"].append(ent.text)
for token in doc:
if token.pos_ == "VERB" and token.text not in augmented_lists["Events"]:
augmented_lists["Events"].append(token.text)
elif token.pos_ == "NOUN" and token.text not in augmented_lists["Characters"] + augmented_lists["Settings"]:
augmented_lists["Objects"].append(token.text)
dialogues = re.findall(r'"[^"]*"', user_input)
augmented_lists["Dialogues"].extend(dialogues)
return augmented_lists
# Function to create a 52-card deck
def create_deck():
suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
ranks = list(range(1, 14)) # 1-13 for each suit
deck = [(suit, rank) for suit in suits for rank in ranks]
random.shuffle(deck)
return deck
# Assign cards to classes based on position
def assign_card_to_class(card_index):
if 0 <= card_index < 10:
return "Characters"
elif 10 <= card_index < 20:
return "Settings"
elif 20 <= card_index < 30:
return "Events"
elif 30 <= card_index < 40:
return "Objects"
else:
return "Dialogues"
# Generate a card image with details
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 based on card
def generate_story_sentence(story_class, word, property):
template = sentence_templates[story_class]
return template.format(word=word, property=property)
# Generate song lyrics from story
def generate_song_lyrics(story_text):
doc = nlp(story_text)
key_elements = [token.text for token in doc if token.pos_ in ["NOUN", "VERB", "ADJ"]][:10] # Top 10 elements
lyrics = " ".join(key_elements) # Simple concatenation for 60-second duration
return lyrics
# Main Streamlit app
def main():
st.title("StoryForge: Card-Based Story Generator")
# User input for story seed
user_input = st.text_area("Paste your story seed here (large text accepted):", height=200)
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 and augment word lists
if st.button("Process Input"):
if user_input:
st.session_state.augmented_lists = augment_word_lists(user_input)
st.session_state.deck = create_deck() # Reset deck
st.session_state.story = []
st.session_state.drawn_cards = 0
st.success("Input processed! Ready to draw cards.")
# Draw card button
if st.button("Draw a 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_list = st.session_state.augmented_lists[story_class]
word = random.choice(word_list)
property = suit_properties[suit]
# Generate and display card image
card_image = generate_card_image(suit, rank, story_class, word, property)
st.image(card_image, caption=f"Card {card_index + 1}")
# Generate and append story sentence
sentence = generate_story_sentence(story_class, word, property)
st.session_state.story.append(sentence)
st.session_state.drawn_cards += 1
# Display current story
st.write("### Current Story")
st.write("\n".join(st.session_state.story))
# Generate song when deck is fully drawn
if st.session_state.drawn_cards == 52:
st.write("### Full Story Generated!")
full_story = "\n".join(st.session_state.story)
st.write(full_story)
# Generate and play song
lyrics = generate_song_lyrics(full_story)
st.write("### Song Lyrics")
st.write(lyrics)
tts = gTTS(text=lyrics, lang="en")
audio_file = "song.mp3"
tts.save(audio_file)
audio_bytes = open(audio_file, "rb").read()
st.audio(audio_bytes, format="audio/mp3")
# Basic p5.js integration for interactivity (placeholder)
st.components.v1.html("""
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
<div id="sketch-holder"></div>
<script>
function setup() {
let canvas = createCanvas(400, 100);
canvas.parent('sketch-holder');
background(220);
textSize(16);
text('Draw cards to build your story!', 10, 50);
}
</script>
""", height=120)
if __name__ == "__main__":
main() |