aghilTQ commited on
Commit
fc32377
·
verified ·
1 Parent(s): bbae9c6

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +66 -115
src/streamlit_app.py CHANGED
@@ -1,5 +1,5 @@
1
  import streamlit as st
2
- import syllables
3
  import re
4
  import random
5
  from typing import List, Tuple
@@ -11,6 +11,11 @@ st.set_page_config(
11
  layout="wide"
12
  )
13
 
 
 
 
 
 
14
  def generate_color_palette(num_colors: int) -> List[str]:
15
  """Generate distinct colors for syllables"""
16
  colors = [
@@ -22,13 +27,13 @@ def generate_color_palette(num_colors: int) -> List[str]:
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
 
@@ -36,107 +41,32 @@ def syllabify_word(word: str) -> List[str]:
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
  # Split into words while preserving spaces
141
  words = re.findall(r'\b\w+\b', text) # Only actual words, no spaces
142
 
@@ -151,7 +81,7 @@ def process_text(text: str) -> Tuple[List[Tuple[str, str]], List[Tuple[str, List
151
  if part.strip() and re.match(r'\w', part): # If it's a word
152
  if word_index < len(words):
153
  word = words[word_index]
154
- syllables_list = syllabify_word(word)
155
 
156
  # Generate colors for this word's syllables
157
  colors = generate_color_palette(len(syllables_list))
@@ -176,15 +106,15 @@ def display_colored_text(colored_words: List[Tuple[str, str]]):
176
  html_parts = []
177
  for word, color in colored_words:
178
  if word.strip():
179
- html_parts.append(f'<span style="color: {color}; font-weight: bold;">{word}</span>')
180
  else:
181
  html_parts.append(word)
182
 
183
  html_content = ''.join(html_parts)
184
- 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)
185
 
186
  def display_syllable_breakdown(syllable_breakdown: List[Tuple[str, List[Tuple[str, str]]]]):
187
- """Display syllable breakdown"""
188
  html_parts = []
189
 
190
  for word, syllables in syllable_breakdown:
@@ -192,24 +122,24 @@ def display_syllable_breakdown(syllable_breakdown: List[Tuple[str, List[Tuple[st
192
  # Create hyphenated syllable display
193
  syllable_spans = []
194
  for syl, color in syllables:
195
- syllable_spans.append(f'<span style="color: {color}; font-weight: bold;">{syl}</span>')
196
 
197
  # Join with hyphens for multi-syllable words
198
  if len(syllables) > 1:
199
- syllable_display = '<span style="color: #666;">-</span>'.join(syllable_spans)
200
  else:
201
  syllable_display = syllable_spans[0]
202
 
203
- html_parts.append(f'<span style="margin-right: 20px; display: inline-block; margin-bottom: 8px;">{syllable_display}</span>')
204
 
205
  if html_parts:
206
  html_content = ''.join(html_parts)
207
- st.markdown(f'<div style="font-size: 18px; line-height: 2.0; padding: 15px; border: 2px solid #ddd; border-radius: 10px; background-color: #f0f8ff;">{html_content}</div>', unsafe_allow_html=True)
208
 
209
  # Main app
210
  def main():
211
  st.title("🔤 Text Syllabification Tool")
212
- st.markdown("Enter text below to see syllable breakdown with color coding!")
213
 
214
  # Input text area
215
  input_text = st.text_area(
@@ -243,25 +173,27 @@ def main():
243
 
244
  # Show syllable counts
245
  if syllable_breakdown:
246
- st.subheader("Syllable Counts")
247
- counts_html = []
248
  for word, syllables in syllable_breakdown:
249
  count = len(syllables)
250
- counts_html.append(f"<span style='margin-right: 15px;'><strong>{word}</strong>: {count}</span>")
251
 
252
- counts_display = " ".join(counts_html)
253
- st.markdown(f'<div style="padding: 10px; background-color: #f0f0f0; border-radius: 5px;">{counts_display}</div>', unsafe_allow_html=True)
 
 
 
254
 
255
  else:
256
  st.info("👆 Enter some text above to see the syllabification in action!")
257
 
258
  # Example
259
  st.subheader("Example")
260
- example_text = "Beautiful mountains and valleys create wonderful landscapes."
261
  st.code(example_text)
262
 
263
  if st.button("Try Example"):
264
- st.session_state.example_clicked = True
265
  # Process example
266
  colored_words, syllable_breakdown = process_text(example_text)
267
 
@@ -274,6 +206,25 @@ def main():
274
  with col2:
275
  st.subheader("Syllable Breakdown")
276
  display_syllable_breakdown(syllable_breakdown)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
  if __name__ == "__main__":
279
  main()
 
1
  import streamlit as st
2
+ import pyphen
3
  import re
4
  import random
5
  from typing import List, Tuple
 
11
  layout="wide"
12
  )
13
 
14
+ # Initialize pyphen dictionary for English
15
+ @st.cache_resource
16
+ def get_pyphen_dict():
17
+ return pyphen.Pyphen(lang='en')
18
+
19
  def generate_color_palette(num_colors: int) -> List[str]:
20
  """Generate distinct colors for syllables"""
21
  colors = [
 
27
 
28
  # If we need more colors than predefined, generate random ones
29
  while len(colors) < num_colors:
30
+ color = f"#{random.randint(100, 255):02x}{random.randint(100, 255):02x}{random.randint(100, 255):02x}"
31
  colors.append(color)
32
 
33
  return colors[:num_colors]
34
 
35
+ def syllabify_word(word: str, pyphen_dict) -> List[str]:
36
+ """Syllabify a single word using pyphen"""
37
  # Clean the word of punctuation for syllabification
38
  clean_word = re.sub(r'[^\w]', '', word)
39
 
 
41
  return [word]
42
 
43
  try:
44
+ # Use pyphen to get syllables
45
+ syllabified = pyphen_dict.inserted(clean_word.lower())
46
+ syllables = syllabified.split('-')
 
 
 
47
 
48
+ # If no syllables found (single syllable word), return the word
49
+ if len(syllables) == 1 and syllables[0] == clean_word.lower():
50
+ return [clean_word]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ # Handle case preservation
53
+ if clean_word.isupper():
54
+ syllables = [syl.upper() for syl in syllables]
55
+ elif clean_word[0].isupper():
56
+ for i, syl in enumerate(syllables):
57
+ if i == 0:
58
+ syllables[i] = syl.capitalize()
59
+ else:
60
+ syllables[i] = syl.lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ return syllables if syllables else [clean_word]
63
+ except:
64
+ return [clean_word]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  def process_text(text: str) -> Tuple[List[Tuple[str, str]], List[Tuple[str, List[Tuple[str, str]]]]]:
67
  """Process text and return colored words and syllable breakdown"""
68
+ pyphen_dict = get_pyphen_dict()
69
+
70
  # Split into words while preserving spaces
71
  words = re.findall(r'\b\w+\b', text) # Only actual words, no spaces
72
 
 
81
  if part.strip() and re.match(r'\w', part): # If it's a word
82
  if word_index < len(words):
83
  word = words[word_index]
84
+ syllables_list = syllabify_word(word, pyphen_dict)
85
 
86
  # Generate colors for this word's syllables
87
  colors = generate_color_palette(len(syllables_list))
 
106
  html_parts = []
107
  for word, color in colored_words:
108
  if word.strip():
109
+ html_parts.append(f'<span style="color: {color}; font-weight: bold; font-size: 18px;">{word}</span>')
110
  else:
111
  html_parts.append(word)
112
 
113
  html_content = ''.join(html_parts)
114
+ st.markdown(f'<div style="font-size: 18px; line-height: 1.8; padding: 20px; border: 2px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">{html_content}</div>', unsafe_allow_html=True)
115
 
116
  def display_syllable_breakdown(syllable_breakdown: List[Tuple[str, List[Tuple[str, str]]]]):
117
+ """Display syllable breakdown with hyphens"""
118
  html_parts = []
119
 
120
  for word, syllables in syllable_breakdown:
 
122
  # Create hyphenated syllable display
123
  syllable_spans = []
124
  for syl, color in syllables:
125
+ syllable_spans.append(f'<span style="color: {color}; font-weight: bold; font-size: 18px;">{syl}</span>')
126
 
127
  # Join with hyphens for multi-syllable words
128
  if len(syllables) > 1:
129
+ syllable_display = '<span style="color: #666; font-weight: bold;">-</span>'.join(syllable_spans)
130
  else:
131
  syllable_display = syllable_spans[0]
132
 
133
+ html_parts.append(f'<span style="margin-right: 25px; display: inline-block; margin-bottom: 12px;">{syllable_display}</span>')
134
 
135
  if html_parts:
136
  html_content = ''.join(html_parts)
137
+ st.markdown(f'<div style="font-size: 18px; line-height: 2.2; padding: 20px; border: 2px solid #ddd; border-radius: 10px; background-color: #f0f8ff;">{html_content}</div>', unsafe_allow_html=True)
138
 
139
  # Main app
140
  def main():
141
  st.title("🔤 Text Syllabification Tool")
142
+ st.markdown("Enter text below to see accurate syllable breakdown with color coding using **pyphen** library!")
143
 
144
  # Input text area
145
  input_text = st.text_area(
 
173
 
174
  # Show syllable counts
175
  if syllable_breakdown:
176
+ st.subheader("Syllable Counts per Word")
177
+ counts_data = []
178
  for word, syllables in syllable_breakdown:
179
  count = len(syllables)
180
+ counts_data.append(f"**{word}**: {count}")
181
 
182
+ # Display in columns for better readability
183
+ cols = st.columns(3)
184
+ for i, count_info in enumerate(counts_data):
185
+ with cols[i % 3]:
186
+ st.markdown(count_info)
187
 
188
  else:
189
  st.info("👆 Enter some text above to see the syllabification in action!")
190
 
191
  # Example
192
  st.subheader("Example")
193
+ example_text = "The preparation of abstracts is an intellectual effort requiring general familiarity."
194
  st.code(example_text)
195
 
196
  if st.button("Try Example"):
 
197
  # Process example
198
  colored_words, syllable_breakdown = process_text(example_text)
199
 
 
206
  with col2:
207
  st.subheader("Syllable Breakdown")
208
  display_syllable_breakdown(syllable_breakdown)
209
+
210
+ # Show example statistics
211
+ total_words = len([word for word, _ in syllable_breakdown])
212
+ total_syllables = sum(len(syls) for _, syls in syllable_breakdown)
213
+ st.markdown(f"**Example Statistics:** {total_words} words, {total_syllables} syllables")
214
+
215
+ # About section
216
+ with st.expander("About this tool"):
217
+ st.markdown("""
218
+ This tool uses the **pyphen** library, which implements the Hunspell hyphenation algorithm.
219
+ It provides much more accurate syllabification than simple rule-based approaches.
220
+
221
+ **Features:**
222
+ - Accurate English syllabification using pyphen
223
+ - Color-coded visualization
224
+ - Preserves original text formatting
225
+ - Shows syllable counts and statistics
226
+ - Handles capitalization properly
227
+ """)
228
 
229
  if __name__ == "__main__":
230
  main()