awacke1 commited on
Commit
e211a6f
·
verified ·
1 Parent(s): d0ac15e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -213
app.py CHANGED
@@ -1,225 +1,191 @@
1
  import streamlit as st
2
- import streamlit.components.v1 as components
3
- import math
 
 
 
 
 
 
4
 
5
- def main():
6
- st.set_page_config(page_title="Storytelling Mastery", page_icon="📚", layout="wide")
7
-
8
- st.title("🎭 The Art of Storytelling: Master Guide 🎭")
9
-
10
- # -----------------------------
11
- # 1. The Storyteller's Song
12
- # -----------------------------
13
- st.markdown("## 🎵 The Storyteller's Journey Song 🎵")
14
- st.markdown("""
15
- **Verse 1 – Location**
16
- *I'm in a quiet town, where twilight meets the dawn,*
17
- *A simple street and weathered walls, where whispered dreams are drawn.*
18
 
19
- **Verse 2 Actions**
20
- *I lace my worn-out sneakers, stepping into a new day’s light,*
21
- *I pedal through cobbled memories, heart racing with each flight.*
 
 
 
 
 
22
 
23
- **Verse 3 Thoughts**
24
- *In every echo of my footsteps, a raw, unfiltered thought appears,*
25
- *I muse, “Am I chasing shadows, or the brilliance of my years?”*
 
 
 
 
26
 
27
- **Verse 4 Emotions**
28
- *My eyes reflect a storm of joy and pain—a silent, candid art,*
29
- *A trembling smile, a furrowed brow, emotions painted on my heart.*
 
 
 
 
 
30
 
31
- **Verse 5 Dialogue**
32
- *Then comes a gentle, piercing voice: “Keep moving, dare to feel;”*
33
- *Those words ignite the darkened skies—my destiny is real.*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- **Chorus**
36
- *Let each moment unfold its magic, in places, moves, and minds so bold,*
37
- *For every whispered thought and burst of feeling tells a story yet untold.*
38
- """)
39
-
40
- st.markdown("---")
41
-
42
- # -----------------------------
43
- # 2. The Storytelling Points Outline
44
- # -----------------------------
45
- storytelling_points = [
46
- {"number": 1, "emoji": "🏠", "keyword": "location", "description": "Set a scene that sparks the imagination: a place that's simply stated but vividly felt."},
47
- {"number": 2, "emoji": "🏃", "keyword": "actions", "description": "Show the kinetic energy—whether it’s walking, biking, or a spontaneous burst of movement."},
48
- {"number": 3, "emoji": "🧠", "keyword": "thoughts", "description": "Reveal those raw, neurotic inner monologues that make you real and relatable."},
49
- {"number": 4, "emoji": "😲", "keyword": "emotions", "description": "Let your body speak the language of your feelings—every twitch and tear is a story."},
50
- {"number": 5, "emoji": "💬", "keyword": "dialogue", "description": "Capture crisp, memorable dialogue that slices through the moment like lightning."},
51
- # Additional points can be used for further storytelling techniques…
52
- ]
53
-
54
- # -----------------------------
55
- # 3. Random Literary Wit – Ten Poetic Lines
56
- # -----------------------------
57
- random_poetry = [
58
- "🌅 Location: Where the horizon kisses the edge of dreams. 🌌",
59
- "🚴 Action: Pedaling through the city's heartbeat, every turn a burst of rhythm. 🎶",
60
- "💭 Thoughts: Whispering secrets of a chaotic mind under a tranquil sky. 🌒",
61
- "😊 Emotions: A smile that trembles like morning dew on a rose. 🌈",
62
- "🗣 Dialogue: Words crackling like fire in the midnight hush. 🔥",
63
- "🌲 Nature: The forest murmurs ancient tales to those who dare to listen. 🍃",
64
- "🌊 Waves: Dancing to the eternal hymn of the deep blue. 🐚",
65
- "🌟 Dreams: Starlight scattered over the canvas of restless nights. ✨",
66
- "🔥 Passion: A flame burning fierce in the silence of despair. ❤️",
67
- "🍂 Reflection: Leaves falling like whispered memories in autumn’s embrace. 🕊️"
68
- ]
69
-
70
- st.markdown("## ✨ Random Literary Wit")
71
- st.code("\n".join(random_poetry), language="python")
72
-
73
- # -----------------------------
74
- # 4. Interactive Story Element Explorer (Vertical Flow and Tabs)
75
- # -----------------------------
76
- st.markdown("## 📚 The Art of Storytelling: 5 Essential Elements")
77
-
78
- st.markdown("> \"The universe is made of stories, not of atoms.\" — Muriel Rukeyser")
79
-
80
- for point in storytelling_points:
81
- st.markdown(f"{point['number']}. {point['emoji']} **{point['keyword'].capitalize()}** - {point['description']}")
82
-
83
- # -----------------------------
84
- # 5. Star Layout for the Five Pillars
85
- # -----------------------------
86
- st.markdown("## ⭐ Five Pillars in a Star Layout ⭐")
87
-
88
- # Using absolute positioning in a relative container to arrange five points on a circle
89
- # Calculated using basic trigonometry (center = 200, radius = 150)
90
- star_html = """
91
- <div style="position: relative; width: 400px; height: 400px; margin: auto; border: 1px dashed #aaa; border-radius: 50%;">
92
- <!-- Point 1: Location at angle 90° -->
93
- <div style="position: absolute; top: 50px; left: 200px; transform: translate(-50%, -50%); text-align: center;">
94
- <div style="font-size: 2em;">🏠</div>
95
- <div><b>Location</b></div>
96
- </div>
97
- <!-- Point 2: Actions at angle ~162° -->
98
- <div style="position: absolute; top: 154px; left: 57px; transform: translate(-50%, -50%); text-align: center;">
99
- <div style="font-size: 2em;">🏃</div>
100
- <div><b>Actions</b></div>
101
- </div>
102
- <!-- Point 3: Thoughts at angle ~234° -->
103
- <div style="position: absolute; top: 321px; left: 112px; transform: translate(-50%, -50%); text-align: center;">
104
- <div style="font-size: 2em;">🧠</div>
105
- <div><b>Thoughts</b></div>
106
- </div>
107
- <!-- Point 4: Emotions at angle ~306° -->
108
- <div style="position: absolute; top: 321px; left: 288px; transform: translate(-50%, -50%); text-align: center;">
109
- <div style="font-size: 2em;">😲</div>
110
- <div><b>Emotions</b></div>
111
- </div>
112
- <!-- Point 5: Dialogue at angle ~18° -->
113
- <div style="position: absolute; top: 154px; left: 343px; transform: translate(-50%, -50%); text-align: center;">
114
- <div style="font-size: 2em;">💬</div>
115
- <div><b>Dialogue</b></div>
116
- </div>
117
- </div>
118
- """
119
- components.html(star_html, height=450)
120
-
121
- # -----------------------------
122
- # 6. Additional Interactive Elements (Tabs & Dropdown)
123
- # -----------------------------
124
- tab1, tab2, tab3 = st.tabs(["Vertical Flow", "Circular Layout", "Categorical Groups"])
125
-
126
- with tab1:
127
- st.markdown("### Vertical Flow Diagram")
128
- mermaid_vertical = generate_vertical_diagram(storytelling_points)
129
- st.markdown(mermaid_vertical, unsafe_allow_html=True)
130
-
131
- with tab2:
132
- st.markdown("### Circular Storytelling Process")
133
- mermaid_circular = generate_circular_diagram(storytelling_points)
134
- st.markdown(mermaid_circular, unsafe_allow_html=True)
135
-
136
- with tab3:
137
- st.markdown("### Categorical Groups")
138
- mermaid_categories = generate_categorical_diagram(storytelling_points)
139
- st.markdown(mermaid_categories, unsafe_allow_html=True)
140
-
141
- st.markdown("## 🔍 Explore Individual Storytelling Elements")
142
- col1, col2 = st.columns([1, 3])
143
-
144
- with col1:
145
- options = [f"{point['number']}. {point['emoji']} {point['keyword'].capitalize()}" for point in storytelling_points]
146
- selected_option = st.selectbox("Select an element to explore:", options)
147
- selected_number = int(selected_option.split('.')[0])
148
- selected_point = next(point for point in storytelling_points if point['number'] == selected_number)
149
-
150
- with col2:
151
- st.markdown(f"### {selected_option}")
152
- st.markdown(f"**Description:** {selected_point['description']}")
153
- examples = {
154
- 1: "'In the stillness of a small town, I take in the crisp air...'",
155
- 2: "'I lace up my sneakers and step boldly into the unknown, each stride a heartbeat.'",
156
- 3: "'I muse: What if these fleeting moments are the stitches of my very soul?'",
157
- 4: "'My eyes shimmer with unspoken stories, my face a canvas of turbulent joy.'",
158
- 5: "'Then, a voice cuts through the silence: ‘Keep pushing, the dawn awaits!’'"
159
- }
160
- st.markdown(f"**Example:** {examples.get(selected_number, 'No example available.')}")
161
-
162
- st.markdown("> \"There is no greater agony than bearing an untold story inside you.\" — Maya Angelou")
163
 
164
- def generate_vertical_diagram(points):
165
- """Generate a vertical flow Mermaid diagram"""
166
- nodes = []
167
- connections = []
168
- styles = []
169
-
170
- for i, point in enumerate(points):
171
- node_id = point['number']
172
- node_label = f"{node_id}. {point['emoji']} {point['keyword'].capitalize()}"
173
- nodes.append(f" {node_id}(\"{node_label}\")")
174
- if i < len(points) - 1:
175
- connections.append(f" {node_id} --> {points[i+1]['number']}")
176
- else:
177
- connections.append(f" {node_id} --> {points[0]['number']}")
178
-
179
- styles.extend([
180
- " %% Style definitions",
181
- " classDef foundation fill:#ff9900,stroke:#333,stroke-width:2px,color:#000;",
182
- " classDef technique fill:#66cc99,stroke:#333,stroke-width:2px,color:#000;",
183
- " classDef learning fill:#6699cc,stroke:#333,stroke-width:2px,color:#000;",
184
- " classDef mastery fill:#cc6699,stroke:#333,stroke-width:2px,color:#000;",
185
- " class 1,2,3,4,5 foundation;"
186
- ])
187
-
188
- diagram = ["```mermaid", "graph TD"]
189
- diagram.extend(nodes)
190
- diagram.extend(connections)
191
- diagram.extend(styles)
192
- diagram.append("```")
193
- return "\n".join(diagram)
194
 
195
- def generate_circular_diagram(points):
196
- """Generate a circular flow Mermaid diagram"""
197
- diagram = ["```mermaid", "graph TD"]
198
- for point in points:
199
- node_id = point['number']
200
- node_label = f"{node_id}. {point['emoji']} {point['keyword'].capitalize()}"
201
- diagram.append(f" {node_id}[\"{node_label}\"]")
202
- diagram.extend([
203
- " 1 --> 2 --> 3 --> 4 --> 5 --> 1",
204
- " %% Style definitions",
205
- " classDef q1 fill:#ff9900,stroke:#333,stroke-width:2px,color:#000;",
206
- " class 1,2,3,4,5 q1;"
207
- ])
208
- diagram.append("```")
209
- return "\n".join(diagram)
210
 
211
- def generate_categorical_diagram(points):
212
- """Generate a categorical Mermaid diagram grouping the storytelling elements"""
213
- diagram = ["```mermaid", "graph TB",
214
- " subgraph Foundation[\"Foundation Elements\"]",
215
- " 1(\"`1. 🏠 Location`\")",
216
- " 2(\"`2. 🏃 Actions`\")",
217
- " 3(\"`3. 🧠 Thoughts`\")",
218
- " 4(\"`4. 😲 Emotions`\")",
219
- " 5(\"`5. 💬 Dialogue`\")",
220
- " end",
221
- "```"]
222
- return "\n".join(diagram)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  if __name__ == "__main__":
225
- main()
 
1
  import streamlit as st
2
+ import spacy
3
+ import random
4
+ import re
5
+ from gtts import gTTS
6
+ from PIL import Image, ImageDraw, ImageFont
7
+ import io
8
+ import numpy as np
9
+ import base64
10
 
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
24
+ suit_properties = {
25
+ "Hearts": "emotional or romantic",
26
+ "Diamonds": "wealthy or luxurious",
27
+ "Clubs": "conflict or struggle",
28
+ "Spades": "mysterious or dangerous"
29
+ }
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)
88
+ font = ImageFont.load_default()
89
+
90
+ draw.text((10, 10), f"{rank} of {suit}", fill="black", font=font)
91
+ draw.text((10, 50), f"Class: {story_class}", fill="black", font=font)
92
+ draw.text((10, 90), f"Word: {word}", fill="black", font=font)
93
+ draw.text((10, 130), f"Property: {property}", fill="black", font=font)
94
+
95
+ buffer = io.BytesIO()
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:
121
+ st.session_state.deck = create_deck()
122
+ if "story" not in st.session_state:
123
+ st.session_state.story = []
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()