duongthienz commited on
Commit
e10e7d3
Β·
verified Β·
1 Parent(s): 473b130

fix bug rename speaker and rename multiple speakers

Browse files
Files changed (1) hide show
  1. state.py +79 -34
state.py CHANGED
@@ -55,7 +55,6 @@ def init_session_state():
55
  "speakerSegments": {}, # {filename: {speaker: [(start,end), ...]}}
56
  "speakerWaveforms": {}, # {filename: (waveform_tensor, sample_rate)}
57
  "globalRenames": [], # [{"name": str, "speakers": ["file: SPEAKER_##", ...]}]
58
- "inlineRenames": {}, # {filename: {speaker: name}} β€” set by Rename Speaker tab only
59
  "analyzeAllToggle": False,
60
  }
61
  for key, value in defaults.items():
@@ -144,36 +143,58 @@ def _global_rename_key(index):
144
 
145
 
146
  def applyGlobalRenames():
147
- """Rebuild speakerRenames from two independent sources:
148
- 1. globalRenames β€” sidebar assignments (always authoritative for tokens it covers)
149
- 2. inlineRenames β€” Rename Speaker tab assignments (used only when globalRenames
150
- has no claim on that token)
151
- Any speaker not covered by either source gets cleared.
 
 
 
 
 
152
  """
153
- # Build token->name map from globalRenames
154
  token_to_name: dict = {}
155
  for entry in st.session_state.globalRenames:
156
  for token in entry["speakers"]:
157
  token_to_name[token] = entry["name"]
158
 
159
- # Rebuild speakerRenames for every file from scratch
160
- for fname in st.session_state.speakerRenames:
161
- new_renames = {}
162
- inline = st.session_state.inlineRenames.get(fname, {})
163
- # Check every known speaker for this file
164
- result = st.session_state.results.get(fname)
165
- if not result or len(result) != 2:
166
- continue
167
- for sp in result[0].labels():
 
 
168
  token = f"{fname}: {sp}"
169
  if token in token_to_name:
170
- # Sidebar assignment wins
171
- new_renames[sp] = token_to_name[token]
172
- elif sp in inline:
173
- # Tab assignment used only when sidebar has no claim
174
- new_renames[sp] = inline[sp]
175
- # else: no assignment β€” omit (raw label will be used)
176
- st.session_state.speakerRenames[fname] = new_renames
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
 
179
  def enforceGlobalRenameExclusivity(changed_idx):
@@ -185,6 +206,7 @@ def enforceGlobalRenameExclusivity(changed_idx):
185
  new_speakers = [t for t in entry["speakers"] if t not in changed_tokens]
186
  if new_speakers != entry["speakers"]:
187
  entry["speakers"] = new_speakers
 
188
  st.session_state.pop(_global_rename_key(idx), None)
189
  applyGlobalRenames()
190
 
@@ -202,7 +224,11 @@ def addGlobalRename():
202
  def removeGlobalRename(index):
203
  entry = st.session_state.globalRenames[index]
204
  st.toast(f"Removing rename '{entry['name']}'")
 
 
 
205
  del st.session_state.globalRenames[index]
 
206
  for i in range(index, len(st.session_state.globalRenames)):
207
  st.session_state[_global_rename_key(i)] = list(
208
  st.session_state.globalRenames[i]["speakers"]
@@ -211,22 +237,42 @@ def removeGlobalRename(index):
211
 
212
 
213
  def apply_inline_rename(currFile, raw_sp, new_name):
214
- """Write a tab-originated rename into inlineRenames, then sync speakerRenames.
215
 
216
- inlineRenames is the sole record of tab renames. applyGlobalRenames() merges
217
- inlineRenames with globalRenames every time it runs, so sidebar assignments
218
- always win and tab assignments fill the rest.
219
  """
220
  new_name = new_name.strip()
 
 
 
 
 
 
 
 
 
221
 
222
- inline = st.session_state.inlineRenames.setdefault(currFile, {})
223
  if new_name:
224
- inline[raw_sp] = new_name
 
 
 
 
 
 
 
 
 
 
 
 
225
  else:
226
- inline.pop(raw_sp, None)
227
-
228
- # Immediately reflect in speakerRenames (sidebar may override on next run)
229
- applyGlobalRenames()
230
 
231
 
232
  # ---------------------------------------------------------------------------
@@ -290,7 +336,6 @@ def register_file(fname):
290
  while len(st.session_state.categorySelect) < len(st.session_state.categories):
291
  st.session_state.categorySelect.append([])
292
  st.session_state.speakerRenames.setdefault(fname, {})
293
- st.session_state.inlineRenames.setdefault(fname, {})
294
  st.session_state.speakerClips.setdefault(fname, {})
295
  if fname not in st.session_state.file_names:
296
  st.session_state.file_names.append(fname)
 
55
  "speakerSegments": {}, # {filename: {speaker: [(start,end), ...]}}
56
  "speakerWaveforms": {}, # {filename: (waveform_tensor, sample_rate)}
57
  "globalRenames": [], # [{"name": str, "speakers": ["file: SPEAKER_##", ...]}]
 
58
  "analyzeAllToggle": False,
59
  }
60
  for key, value in defaults.items():
 
143
 
144
 
145
  def applyGlobalRenames():
146
+ """Sync speakerRenames (and inline tab widget keys) from globalRenames.
147
+
148
+ Strategy:
149
+ - Speakers assigned in globalRenames β†’ rename to the entry's name.
150
+ - Speakers whose token appears in NO globalRenames entry but whose raw_sp
151
+ is not in speakerRenames for any other reason β†’ clear the rename.
152
+ - Speakers with a speakerRenames entry that was set purely inline (never
153
+ tracked in globalRenames) β†’ left untouched.
154
+ After updating speakerRenames, we re-seed every rename_{fname}_{sp} widget
155
+ key so the Rename Speaker tab immediately reflects the change.
156
  """
157
+ # Build a map of token -> display_name from globalRenames
158
  token_to_name: dict = {}
159
  for entry in st.session_state.globalRenames:
160
  for token in entry["speakers"]:
161
  token_to_name[token] = entry["name"]
162
 
163
+ # Every token that has EVER appeared in globalRenames (used to detect removal)
164
+ all_global_tokens: set = {
165
+ token
166
+ for entry in st.session_state.globalRenames
167
+ for token in entry["speakers"]
168
+ }
169
+
170
+ # 1. Update speakerRenames for files already tracked
171
+ for fname in list(st.session_state.speakerRenames.keys()):
172
+ renames = st.session_state.speakerRenames[fname]
173
+ for sp in list(renames.keys()):
174
  token = f"{fname}: {sp}"
175
  if token in token_to_name:
176
+ renames[sp] = token_to_name[token]
177
+ elif token in all_global_tokens:
178
+ # Was globally tracked but now unassigned β€” revert to raw label
179
+ del renames[sp]
180
+ # else: purely inline rename β€” leave untouched
181
+
182
+ # 2. Apply newly assigned tokens not yet in speakerRenames
183
+ for token, name in token_to_name.items():
184
+ if ": " not in token:
185
+ continue
186
+ fname, raw_sp = token.split(": ", 1)
187
+ if fname in st.session_state.speakerRenames:
188
+ st.session_state.speakerRenames[fname][raw_sp] = name
189
+
190
+ # 3. Sync the inline-tab widget keys (rename_{fname}_{sp}) for every
191
+ # analyzed file so the Rename Speaker tab shows the updated names.
192
+ for fname, renames in st.session_state.speakerRenames.items():
193
+ results = st.session_state.results.get(fname)
194
+ if not results or len(results) != 2:
195
+ continue
196
+ for sp in results[0].labels():
197
+ st.session_state[f"rename_{fname}_{sp}"] = renames.get(sp, "")
198
 
199
 
200
  def enforceGlobalRenameExclusivity(changed_idx):
 
206
  new_speakers = [t for t in entry["speakers"] if t not in changed_tokens]
207
  if new_speakers != entry["speakers"]:
208
  entry["speakers"] = new_speakers
209
+ # Clear widget key so it re-seeds from updated entry data on next render
210
  st.session_state.pop(_global_rename_key(idx), None)
211
  applyGlobalRenames()
212
 
 
224
  def removeGlobalRename(index):
225
  entry = st.session_state.globalRenames[index]
226
  st.toast(f"Removing rename '{entry['name']}'")
227
+ # Clear the widget key for the deleted entry so Streamlit doesn't try to
228
+ # render it after it no longer exists in globalRenames.
229
+ st.session_state.pop(_global_rename_key(index), None)
230
  del st.session_state.globalRenames[index]
231
+ # Shift remaining widget keys down by one position
232
  for i in range(index, len(st.session_state.globalRenames)):
233
  st.session_state[_global_rename_key(i)] = list(
234
  st.session_state.globalRenames[i]["speakers"]
 
237
 
238
 
239
  def apply_inline_rename(currFile, raw_sp, new_name):
240
+ """Write a single inline rename into both speakerRenames and globalRenames.
241
 
242
+ Keeps the sidebar global-rename list in sync so applyGlobalRenames()
243
+ won't overwrite the change on the next rerun. Also syncs the inline-tab
244
+ widget key so the Rename Speaker tab reflects the result immediately.
245
  """
246
  new_name = new_name.strip()
247
+ token = f"{currFile}: {raw_sp}"
248
+
249
+ # Remove this token from every existing globalRenames entry first β€” a token
250
+ # must belong to at most one name. Clear the sidebar widget key so it
251
+ # re-seeds from the updated entry data on the next render pass.
252
+ for idx, entry in enumerate(st.session_state.globalRenames):
253
+ if token in entry["speakers"]:
254
+ entry["speakers"].remove(token)
255
+ st.session_state.pop(_global_rename_key(idx), None)
256
 
 
257
  if new_name:
258
+ # Write into speakerRenames immediately
259
+ st.session_state.speakerRenames.setdefault(currFile, {})[raw_sp] = new_name
260
+ # Sync the inline-tab text widget so the tab shows the confirmed name
261
+ st.session_state[f"rename_{currFile}_{raw_sp}"] = new_name
262
+ # Find an existing globalRenames entry for this name, or create one
263
+ for idx, entry in enumerate(st.session_state.globalRenames):
264
+ if entry["name"] == new_name:
265
+ entry["speakers"].append(token)
266
+ st.session_state.pop(_global_rename_key(idx), None)
267
+ return
268
+ # No existing entry β€” create a new one; don't pre-set widget key,
269
+ # the render loop will seed it from entry["speakers"] on the next pass.
270
+ st.session_state.globalRenames.append({"name": new_name, "speakers": [token]})
271
  else:
272
+ # Empty name β€” revert this speaker back to its raw label.
273
+ st.session_state.speakerRenames.setdefault(currFile, {}).pop(raw_sp, None)
274
+ # Clear the inline-tab text widget so the tab shows the raw SPEAKER_## label
275
+ st.session_state[f"rename_{currFile}_{raw_sp}"] = ""
276
 
277
 
278
  # ---------------------------------------------------------------------------
 
336
  while len(st.session_state.categorySelect) < len(st.session_state.categories):
337
  st.session_state.categorySelect.append([])
338
  st.session_state.speakerRenames.setdefault(fname, {})
 
339
  st.session_state.speakerClips.setdefault(fname, {})
340
  if fname not in st.session_state.file_names:
341
  st.session_state.file_names.append(fname)