aghilTQ commited on
Commit
5711229
·
verified ·
1 Parent(s): cbb5d64

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +282 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,284 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import syllables
3
+ import re
4
+ import random
5
+ from typing import List, Tuple
6
 
7
+ # Configure page
8
+ st.set_page_config(
9
+ page_title="Text Syllabification Tool",
10
+ page_icon="🔤",
11
+ layout="wide"
12
+ )
13
+
14
+ def generate_color_palette(num_colors: int) -> List[str]:
15
+ """Generate distinct colors for syllables"""
16
+ colors = [
17
+ "#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7",
18
+ "#DDA0DD", "#98D8C8", "#F7DC6F", "#BB8FCE", "#85C1E9",
19
+ "#F8C471", "#82E0AA", "#F1948A", "#85C1E9", "#D7BDE2",
20
+ "#A9DFBF", "#F9E79F", "#D5A6BD", "#AED6F1", "#ABEBC6"
21
+ ]
22
+
23
+ # If we need more colors than predefined, generate random ones
24
+ while len(colors) < num_colors:
25
+ color = f"#{random.randint(0, 255):02x}{random.randint(0, 255):02x}{random.randint(0, 255):02x}"
26
+ colors.append(color)
27
+
28
+ return colors[:num_colors]
29
+
30
+ def syllabify_word(word: str) -> List[str]:
31
+ """Syllabify a single word using the syllables library"""
32
+ # Clean the word of punctuation for syllabification
33
+ clean_word = re.sub(r'[^\w]', '', word)
34
+
35
+ if not clean_word:
36
+ return [word]
37
+
38
+ try:
39
+ # Get syllable count
40
+ syl_count = syllables.estimate(clean_word)
41
+
42
+ # For basic syllabification, we'll use a simple approach
43
+ # The syllables library mainly provides counts, so we'll implement basic rules
44
+ syllable_list = simple_syllabify(clean_word)
45
+
46
+ # If our simple method doesn't match the count, adjust
47
+ if len(syllable_list) != syl_count and syl_count > 0:
48
+ syllable_list = adjust_syllables(clean_word, syl_count)
49
+
50
+ return syllable_list
51
+ except:
52
+ return [word]
53
+
54
+ def simple_syllabify(word: str) -> List[str]:
55
+ """Simple syllabification based on vowel patterns"""
56
+ word = word.lower()
57
+ vowels = "aeiouy"
58
+ syllables_list = []
59
+ current_syllable = ""
60
+
61
+ i = 0
62
+ while i < len(word):
63
+ current_syllable += word[i]
64
+
65
+ # If current character is a vowel
66
+ if word[i] in vowels:
67
+ # Look ahead for consonant clusters
68
+ consonant_cluster = ""
69
+ j = i + 1
70
+ while j < len(word) and word[j] not in vowels:
71
+ consonant_cluster += word[j]
72
+ j += 1
73
+
74
+ # If we're at the end of the word, add everything
75
+ if j >= len(word):
76
+ current_syllable += consonant_cluster
77
+ syllables_list.append(current_syllable)
78
+ break
79
+
80
+ # Split consonant cluster
81
+ if len(consonant_cluster) <= 1:
82
+ # Single consonant goes with next syllable
83
+ syllables_list.append(current_syllable)
84
+ current_syllable = consonant_cluster
85
+ else:
86
+ # Multiple consonants: split them
87
+ split_point = len(consonant_cluster) // 2
88
+ current_syllable += consonant_cluster[:split_point]
89
+ syllables_list.append(current_syllable)
90
+ current_syllable = consonant_cluster[split_point:]
91
+
92
+ i = j - 1
93
+
94
+ i += 1
95
+
96
+ if current_syllable:
97
+ if syllables_list:
98
+ syllables_list[-1] += current_syllable
99
+ else:
100
+ syllables_list.append(current_syllable)
101
+
102
+ return syllables_list if syllables_list else [word]
103
+
104
+ def adjust_syllables(word: str, target_count: int) -> List[str]:
105
+ """Adjust syllable split to match target count"""
106
+ simple_split = simple_syllabify(word)
107
+
108
+ if len(simple_split) == target_count:
109
+ return simple_split
110
+
111
+ # If we have fewer syllables than target, try to split more
112
+ if len(simple_split) < target_count:
113
+ # Split longest syllable
114
+ longest_idx = max(range(len(simple_split)), key=lambda i: len(simple_split[i]))
115
+ longest = simple_split[longest_idx]
116
+
117
+ if len(longest) > 2:
118
+ mid = len(longest) // 2
119
+ simple_split[longest_idx:longest_idx+1] = [longest[:mid], longest[mid:]]
120
+
121
+ # If we have more syllables than target, try to merge
122
+ elif len(simple_split) > target_count and len(simple_split) > 1:
123
+ # Merge shortest adjacent syllables
124
+ min_combined_len = float('inf')
125
+ merge_idx = 0
126
+
127
+ for i in range(len(simple_split) - 1):
128
+ combined_len = len(simple_split[i]) + len(simple_split[i + 1])
129
+ if combined_len < min_combined_len:
130
+ min_combined_len = combined_len
131
+ merge_idx = i
132
+
133
+ merged = simple_split[merge_idx] + simple_split[merge_idx + 1]
134
+ simple_split[merge_idx:merge_idx+2] = [merged]
135
+
136
+ return simple_split
137
+
138
+ def process_text(text: str) -> Tuple[List[Tuple[str, str]], List[Tuple[str, List[Tuple[str, str]]]]]:
139
+ """Process text and return colored words and syllable breakdown"""
140
+ words = re.findall(r'\S+|\s+', text) # Keep spaces
141
+
142
+ colored_words = []
143
+ syllable_breakdown = []
144
+
145
+ for word in words:
146
+ if word.strip(): # If it's a word (not just whitespace)
147
+ syllables_list = syllabify_word(word.strip())
148
+
149
+ # Generate colors for this word's syllables
150
+ colors = generate_color_palette(len(syllables_list))
151
+
152
+ # For original text coloring, we need to map syllables back to original word
153
+ word_colored = []
154
+ syllable_colored = []
155
+
156
+ # Handle punctuation
157
+ clean_word = re.sub(r'[^\w]', '', word.strip())
158
+ prefix_punct = re.match(r'^[^\w]*', word.strip()).group()
159
+ suffix_punct = re.search(r'[^\w]*$', word.strip()).group()
160
+
161
+ if clean_word:
162
+ # Color each syllable
163
+ for i, syl in enumerate(syllables_list):
164
+ color = colors[i % len(colors)]
165
+ syllable_colored.append((syl, color))
166
+
167
+ # For the original word, we'll color it uniformly with the first syllable color
168
+ # or create a gradient effect
169
+ word_with_punct = prefix_punct + clean_word + suffix_punct
170
+ colored_words.append((word_with_punct, colors[0] if colors else "#000000"))
171
+
172
+ syllable_breakdown.append((word.strip(), syllable_colored))
173
+ else:
174
+ colored_words.append((word, "#000000"))
175
+ else:
176
+ colored_words.append((word, "#000000")) # Spaces remain uncolored
177
+
178
+ return colored_words, syllable_breakdown
179
+
180
+ def display_colored_text(colored_words: List[Tuple[str, str]]):
181
+ """Display text with colored words"""
182
+ html_parts = []
183
+ for word, color in colored_words:
184
+ if word.strip():
185
+ html_parts.append(f'<span style="color: {color}; font-weight: bold;">{word}</span>')
186
+ else:
187
+ html_parts.append(word)
188
+
189
+ html_content = ''.join(html_parts)
190
+ st.markdown(f'<div style="font-size: 18px; line-height: 1.6; padding: 15px; border: 2px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">{html_content}</div>', unsafe_allow_html=True)
191
+
192
+ def display_syllable_breakdown(syllable_breakdown: List[Tuple[str, List[Tuple[str, str]]]]):
193
+ """Display syllable breakdown"""
194
+ html_parts = []
195
+
196
+ for word, syllables in syllable_breakdown:
197
+ if syllables:
198
+ word_html = []
199
+ for syl, color in syllables:
200
+ word_html.append(f'<span style="color: {color}; font-weight: bold; margin-right: 2px;">{syl}</span>')
201
+
202
+ # Add separator between syllables
203
+ syllable_display = '<span style="color: #666;">|</span>'.join([
204
+ f'<span style="color: {color}; font-weight: bold;">{syl}</span>'
205
+ for syl, color in syllables
206
+ ])
207
+
208
+ html_parts.append(f'<div style="margin-bottom: 10px;"><strong>{word}:</strong> {syllable_display}</div>')
209
+
210
+ if html_parts:
211
+ html_content = ''.join(html_parts)
212
+ st.markdown(f'<div style="font-size: 16px; line-height: 1.8; padding: 15px; border: 2px solid #ddd; border-radius: 10px; background-color: #f0f8ff;">{html_content}</div>', unsafe_allow_html=True)
213
+
214
+ # Main app
215
+ def main():
216
+ st.title("🔤 Text Syllabification Tool")
217
+ st.markdown("Enter text below to see syllable breakdown with color coding!")
218
+
219
+ # Input text area
220
+ input_text = st.text_area(
221
+ "Enter your text:",
222
+ placeholder="Type or paste your text here...",
223
+ height=150,
224
+ help="Enter any text to see how words are broken down into syllables"
225
+ )
226
+
227
+ if input_text.strip():
228
+ # Process the text
229
+ colored_words, syllable_breakdown = process_text(input_text)
230
+
231
+ # Create two columns
232
+ col1, col2 = st.columns(2)
233
+
234
+ with col1:
235
+ st.subheader("Original Text (Colored by First Syllable)")
236
+ display_colored_text(colored_words)
237
+
238
+ with col2:
239
+ st.subheader("Syllable Breakdown")
240
+ display_syllable_breakdown(syllable_breakdown)
241
+
242
+ # Statistics
243
+ total_words = len([word for word, _ in syllable_breakdown])
244
+ total_syllables = sum(len(syls) for _, syls in syllable_breakdown)
245
+
246
+ st.markdown("---")
247
+ st.markdown(f"**Statistics:** {total_words} words, {total_syllables} syllables")
248
+
249
+ # Show syllable counts
250
+ if syllable_breakdown:
251
+ st.subheader("Syllable Counts")
252
+ counts_html = []
253
+ for word, syllables in syllable_breakdown:
254
+ count = len(syllables)
255
+ counts_html.append(f"<span style='margin-right: 15px;'><strong>{word}</strong>: {count}</span>")
256
+
257
+ counts_display = " ".join(counts_html)
258
+ st.markdown(f'<div style="padding: 10px; background-color: #f0f0f0; border-radius: 5px;">{counts_display}</div>', unsafe_allow_html=True)
259
+
260
+ else:
261
+ st.info("👆 Enter some text above to see the syllabification in action!")
262
+
263
+ # Example
264
+ st.subheader("Example")
265
+ example_text = "Beautiful mountains and valleys create wonderful landscapes."
266
+ st.code(example_text)
267
+
268
+ if st.button("Try Example"):
269
+ st.session_state.example_clicked = True
270
+ # Process example
271
+ colored_words, syllable_breakdown = process_text(example_text)
272
+
273
+ col1, col2 = st.columns(2)
274
+
275
+ with col1:
276
+ st.subheader("Original Text (Colored)")
277
+ display_colored_text(colored_words)
278
+
279
+ with col2:
280
+ st.subheader("Syllable Breakdown")
281
+ display_syllable_breakdown(syllable_breakdown)
282
+
283
+ if __name__ == "__main__":
284
+ main()