awacke1 commited on
Commit
8a22239
ยท
verified ยท
1 Parent(s): 4969c9a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -82
app.py CHANGED
@@ -1,4 +1,5 @@
1
  import streamlit as st
 
2
  import spacy
3
  import random
4
  import re
@@ -11,13 +12,13 @@ import base64
11
  # Load spaCy model for NLP
12
  nlp = spacy.load("en_core_web_sm")
13
 
14
- # Default word lists for storytelling classes
15
  default_word_lists = {
16
- "Characters": ["Hero", "Villain", "Protagonist", "Antagonist", "Wizard", "Knight"],
17
- "Settings": ["Forest", "City", "Castle", "Beach", "Mountain", "Space"],
18
- "Events": ["Adventure", "Romance", "Mystery", "Conflict", "Discovery", "Escape"],
19
- "Objects": ["Sword", "Magic potion", "Treasure chest", "Book", "Ring", "Spaceship"],
20
- "Dialogues": ["\"Hello, how are you?\"", "\"Let's go!\"", "\"Beware the danger!\"", "\"I love you.\""]
21
  }
22
 
23
  # Suit properties for narrative flavor
@@ -30,58 +31,58 @@ suit_properties = {
30
 
31
  # Sentence templates for story generation
32
  sentence_templates = {
33
- "Characters": "There was a {word} who was {property}.",
34
- "Settings": "The {word} was {property}, stretching far into the distance.",
35
- "Events": "Then, a {property} {word} unfolded.",
36
- "Objects": "A {property} {word} appeared before them.",
37
- "Dialogues": "One of them said, {word}, with a {property} tone."
38
  }
39
 
40
  # Function to process user input and augment word lists
41
  def augment_word_lists(user_input):
42
  doc = nlp(user_input)
43
- augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()} # Start with defaults
44
 
45
- # Extract elements from user input
46
  for ent in doc.ents:
47
- if ent.label_ == "PERSON":
48
- augmented_lists["Characters"].append(ent.text)
49
- elif ent.label_ in ["GPE", "LOC"]:
50
- augmented_lists["Settings"].append(ent.text)
51
 
52
  for token in doc:
53
- if token.pos_ == "VERB" and token.text not in augmented_lists["Events"]:
54
- augmented_lists["Events"].append(token.text)
55
- elif token.pos_ == "NOUN" and token.text not in augmented_lists["Characters"] + augmented_lists["Settings"]:
56
- augmented_lists["Objects"].append(token.text)
 
 
 
57
 
58
  dialogues = re.findall(r'"[^"]*"', user_input)
59
- augmented_lists["Dialogues"].extend(dialogues)
60
 
61
  return augmented_lists
62
 
63
- # Function to create a 52-card deck
64
  def create_deck():
65
  suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
66
- ranks = list(range(1, 14)) # 1-13 for each suit
67
  deck = [(suit, rank) for suit in suits for rank in ranks]
68
  random.shuffle(deck)
69
  return deck
70
 
71
- # Assign cards to classes based on position
72
  def assign_card_to_class(card_index):
73
  if 0 <= card_index < 10:
74
- return "Characters"
75
  elif 10 <= card_index < 20:
76
- return "Settings"
77
  elif 20 <= card_index < 30:
78
- return "Events"
79
  elif 30 <= card_index < 40:
80
- return "Objects"
81
  else:
82
- return "Dialogues"
83
 
84
- # Generate a card image with details
85
  def generate_card_image(suit, rank, story_class, word, property):
86
  img = Image.new("RGB", (200, 300), color="white")
87
  draw = ImageDraw.Draw(img)
@@ -96,25 +97,27 @@ def generate_card_image(suit, rank, story_class, word, property):
96
  img.save(buffer, format="PNG")
97
  return buffer.getvalue()
98
 
99
- # Generate story sentence based on card
100
  def generate_story_sentence(story_class, word, property):
101
- template = sentence_templates[story_class]
102
- return template.format(word=word, property=property)
103
 
104
- # Generate song lyrics from story
105
  def generate_song_lyrics(story_text):
106
  doc = nlp(story_text)
107
- key_elements = [token.text for token in doc if token.pos_ in ["NOUN", "VERB", "ADJ"]][:10] # Top 10 elements
108
- lyrics = " ".join(key_elements) # Simple concatenation for 60-second duration
109
  return lyrics
110
 
111
- # Main Streamlit app
112
  def main():
113
- st.title("StoryForge: Card-Based Story Generator")
 
114
 
115
- # User input for story seed
116
- user_input = st.text_area("Paste your story seed here (large text accepted):", height=200)
 
117
 
 
118
  if "augmented_lists" not in st.session_state:
119
  st.session_state.augmented_lists = default_word_lists
120
  if "deck" not in st.session_state:
@@ -124,68 +127,94 @@ def main():
124
  if "drawn_cards" not in st.session_state:
125
  st.session_state.drawn_cards = 0
126
 
127
- # Process input and augment word lists
128
- if st.button("Process Input"):
129
  if user_input:
130
  st.session_state.augmented_lists = augment_word_lists(user_input)
131
- st.session_state.deck = create_deck() # Reset deck
132
  st.session_state.story = []
133
  st.session_state.drawn_cards = 0
134
- st.success("Input processed! Ready to draw cards.")
135
 
136
- # Draw card button
137
- if st.button("Draw a Card") and st.session_state.drawn_cards < 52:
138
- card_index = st.session_state.drawn_cards
139
- suit, rank = st.session_state.deck[card_index]
140
- story_class = assign_card_to_class(card_index)
141
- word_list = st.session_state.augmented_lists[story_class]
142
- word = random.choice(word_list)
143
- property = suit_properties[suit]
144
-
145
- # Generate and display card image
146
- card_image = generate_card_image(suit, rank, story_class, word, property)
147
- st.image(card_image, caption=f"Card {card_index + 1}")
148
-
149
- # Generate and append story sentence
150
- sentence = generate_story_sentence(story_class, word, property)
151
- st.session_state.story.append(sentence)
152
- st.session_state.drawn_cards += 1
153
-
154
- # Display current story
155
- st.write("### Current Story")
156
- st.write("\n".join(st.session_state.story))
157
 
158
- # Generate song when deck is fully drawn
159
  if st.session_state.drawn_cards == 52:
160
- st.write("### Full Story Generated!")
161
  full_story = "\n".join(st.session_state.story)
162
- st.write(full_story)
163
-
164
- # Generate and play song
165
  lyrics = generate_song_lyrics(full_story)
166
- st.write("### Song Lyrics")
167
  st.write(lyrics)
168
 
169
  tts = gTTS(text=lyrics, lang="en")
170
- audio_file = "song.mp3"
171
  tts.save(audio_file)
172
- audio_bytes = open(audio_file, "rb").read()
173
- st.audio(audio_bytes, format="audio/mp3")
174
 
175
- # Basic p5.js integration for interactivity (placeholder)
176
- st.components.v1.html("""
 
177
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
178
  <div id="sketch-holder"></div>
179
  <script>
180
  function setup() {
181
- let canvas = createCanvas(400, 100);
182
  canvas.parent('sketch-holder');
183
- background(220);
184
- textSize(16);
185
- text('Draw cards to build your story!', 10, 50);
 
 
 
 
 
 
 
186
  }
187
  </script>
188
- """, height=120)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  if __name__ == "__main__":
191
  main()
 
1
  import streamlit as st
2
+ import streamlit.components.v1 as components
3
  import spacy
4
  import random
5
  import re
 
12
  # Load spaCy model for NLP
13
  nlp = spacy.load("en_core_web_sm")
14
 
15
+ # Default word lists for storytelling classes (derived from original app)
16
  default_word_lists = {
17
+ "Location": ["quiet town", "small village", "city", "forest", "mountain"],
18
+ "Actions": ["walking", "pedaling", "running", "dancing", "exploring"],
19
+ "Thoughts": ["chasing shadows", "what if", "brilliance of years", "echoes", "secrets"],
20
+ "Emotions": ["joy", "pain", "trembling smile", "storm", "silent art"],
21
+ "Dialogue": ["\"Keep moving, dare to feel;\"", "\"Am I chasing shadows?\"", "\"The dawn awaits!\"", "\"I love you.\"", "\"Letโ€™s go!\""]
22
  }
23
 
24
  # Suit properties for narrative flavor
 
31
 
32
  # Sentence templates for story generation
33
  sentence_templates = {
34
+ "Location": "The story unfolded in a {property} {word}.",
35
+ "Actions": "Suddenly, a {property} {word} changed everything.",
36
+ "Thoughts": "A {property} thought, '{word}', crossed their mind.",
37
+ "Emotions": "A {property} wave of {word} surged through them.",
38
+ "Dialogue": "Someone spoke with a {property} tone: {word}"
39
  }
40
 
41
  # Function to process user input and augment word lists
42
  def augment_word_lists(user_input):
43
  doc = nlp(user_input)
44
+ augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()}
45
 
 
46
  for ent in doc.ents:
47
+ if ent.label_ in ["GPE", "LOC"]:
48
+ augmented_lists["Location"].append(ent.text)
 
 
49
 
50
  for token in doc:
51
+ if token.pos_ == "VERB" and token.text not in augmented_lists["Actions"]:
52
+ augmented_lists["Actions"].append(token.text)
53
+ elif token.pos_ == "NOUN" and token.text not in augmented_lists["Location"]:
54
+ if "emotion" in token.text.lower() or token.text in ["joy", "pain", "smile"]:
55
+ augmented_lists["Emotions"].append(token.text)
56
+ else:
57
+ augmented_lists["Thoughts"].append(token.text)
58
 
59
  dialogues = re.findall(r'"[^"]*"', user_input)
60
+ augmented_lists["Dialogue"].extend(dialogues)
61
 
62
  return augmented_lists
63
 
64
+ # Create a 52-card deck
65
  def create_deck():
66
  suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
67
+ ranks = list(range(1, 14))
68
  deck = [(suit, rank) for suit in suits for rank in ranks]
69
  random.shuffle(deck)
70
  return deck
71
 
72
+ # Assign cards to classes
73
  def assign_card_to_class(card_index):
74
  if 0 <= card_index < 10:
75
+ return "Location"
76
  elif 10 <= card_index < 20:
77
+ return "Actions"
78
  elif 20 <= card_index < 30:
79
+ return "Thoughts"
80
  elif 30 <= card_index < 40:
81
+ return "Emotions"
82
  else:
83
+ return "Dialogue"
84
 
85
+ # Generate card image
86
  def generate_card_image(suit, rank, story_class, word, property):
87
  img = Image.new("RGB", (200, 300), color="white")
88
  draw = ImageDraw.Draw(img)
 
97
  img.save(buffer, format="PNG")
98
  return buffer.getvalue()
99
 
100
+ # Generate story sentence
101
  def generate_story_sentence(story_class, word, property):
102
+ return sentence_templates[story_class].format(word=word, property=property)
 
103
 
104
+ # Generate song lyrics
105
  def generate_song_lyrics(story_text):
106
  doc = nlp(story_text)
107
+ key_elements = [token.text for token in doc if token.pos_ in ["NOUN", "VERB", "ADJ"]][:12] # ~60 seconds
108
+ lyrics = "\n".join([f"{key_elements[i]} {key_elements[i+1]}" for i in range(0, len(key_elements)-1, 2)])
109
  return lyrics
110
 
111
+ # Main app
112
  def main():
113
+ st.set_page_config(page_title="StoryForge: The Game", page_icon="๐ŸŽด", layout="wide")
114
+ st.title("๐ŸŽด StoryForge: A Storytelling Adventure ๐ŸŽด")
115
 
116
+ # User input
117
+ st.markdown("## ๐Ÿ“ Your Story Seed")
118
+ user_input = st.text_area("Paste your story inspiration here:", height=200)
119
 
120
+ # Session state initialization
121
  if "augmented_lists" not in st.session_state:
122
  st.session_state.augmented_lists = default_word_lists
123
  if "deck" not in st.session_state:
 
127
  if "drawn_cards" not in st.session_state:
128
  st.session_state.drawn_cards = 0
129
 
130
+ # Process input
131
+ if st.button("Start Game"):
132
  if user_input:
133
  st.session_state.augmented_lists = augment_word_lists(user_input)
134
+ st.session_state.deck = create_deck()
135
  st.session_state.story = []
136
  st.session_state.drawn_cards = 0
137
+ st.success("Game started! Draw your first card.")
138
 
139
+ # Draw card
140
+ col1, col2 = st.columns([1, 3])
141
+ with col1:
142
+ if st.button("Draw Card") and st.session_state.drawn_cards < 52:
143
+ card_index = st.session_state.drawn_cards
144
+ suit, rank = st.session_state.deck[card_index]
145
+ story_class = assign_card_to_class(card_index)
146
+ word = random.choice(st.session_state.augmented_lists[story_class])
147
+ property = suit_properties[suit]
148
+
149
+ card_image = generate_card_image(suit, rank, story_class, word, property)
150
+ st.image(card_image, caption=f"Card {card_index + 1}")
151
+
152
+ sentence = generate_story_sentence(story_class, word, property)
153
+ st.session_state.story.append(sentence)
154
+ st.session_state.drawn_cards += 1
155
+
156
+ with col2:
157
+ st.markdown("### ๐Ÿ“œ Your Story Unfolds")
158
+ if st.session_state.story:
159
+ st.write("\n".join(st.session_state.story))
160
 
161
+ # Song generation
162
  if st.session_state.drawn_cards == 52:
 
163
  full_story = "\n".join(st.session_state.story)
164
+ st.markdown("### ๐ŸŽต Story Song")
 
 
165
  lyrics = generate_song_lyrics(full_story)
 
166
  st.write(lyrics)
167
 
168
  tts = gTTS(text=lyrics, lang="en")
169
+ audio_file = "story_song.mp3"
170
  tts.save(audio_file)
171
+ st.audio(audio_file, format="audio/mp3")
 
172
 
173
+ # Enhanced UI with p5.js
174
+ st.markdown("## ๐ŸŽฎ Game Board")
175
+ components.html("""
176
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
177
  <div id="sketch-holder"></div>
178
  <script>
179
  function setup() {
180
+ let canvas = createCanvas(600, 200);
181
  canvas.parent('sketch-holder');
182
+ background(240);
183
+ textSize(20);
184
+ textAlign(CENTER);
185
+ text('Draw cards to weave your epic tale!', width/2, height/2);
186
+ }
187
+ function draw() {
188
+ if (mouseIsPressed) {
189
+ fill(255, 0, 0);
190
+ ellipse(mouseX, mouseY, 20, 20);
191
+ }
192
  }
193
  </script>
194
+ """, height=220)
195
+
196
+ # Retain original star layout
197
+ st.markdown("## โญ Five Pillars of Storytelling โญ")
198
+ star_html = """
199
+ <div style="position: relative; width: 400px; height: 400px; margin: auto; border: 1px dashed #aaa; border-radius: 50%;">
200
+ <div style="position: absolute; top: 50px; left: 200px; transform: translate(-50%, -50%); text-align: center;">
201
+ <div style="font-size: 2em;">๐Ÿ </div><div><b>Location</b></div>
202
+ </div>
203
+ <div style="position: absolute; top: 154px; left: 57px; transform: translate(-50%, -50%); text-align: center;">
204
+ <div style="font-size: 2em;">๐Ÿƒ</div><div><b>Actions</b></div>
205
+ </div>
206
+ <div style="position: absolute; top: 321px; left: 112px; transform: translate(-50%, -50%); text-align: center;">
207
+ <div style="font-size: 2em;">๐Ÿง </div><div><b>Thoughts</b></div>
208
+ </div>
209
+ <div style="position: absolute; top: 321px; left: 288px; transform: translate(-50%, -50%); text-align: center;">
210
+ <div style="font-size: 2em;">๐Ÿ˜ฒ</div><div><b>Emotions</b></div>
211
+ </div>
212
+ <div style="position: absolute; top: 154px; left: 343px; transform: translate(-50%, -50%); text-align: center;">
213
+ <div style="font-size: 2em;">๐Ÿ’ฌ</div><div><b>Dialogue</b></div>
214
+ </div>
215
+ </div>
216
+ """
217
+ components.html(star_html, height=450)
218
 
219
  if __name__ == "__main__":
220
  main()