Spaces:
Sleeping
Sleeping
Update state.py
Browse files
state.py
CHANGED
|
@@ -5,7 +5,8 @@ Covers:
|
|
| 5 |
- init_session_state()
|
| 6 |
- Speaker rename helpers (get_display_name, apply_speaker_renames_to_df)
|
| 7 |
- Category callbacks (addCategory, removeCategory, updateCategoryOptions)
|
| 8 |
-
- Global rename callbacks (addGlobalRename, removeGlobalRename,
|
|
|
|
| 9 |
- File-switch callback (updateMultiSelect)
|
| 10 |
- analyze() β builds and caches all DataFrames for a single file
|
| 11 |
- convert_df(), printV()
|
|
@@ -42,8 +43,8 @@ def init_session_state():
|
|
| 42 |
"results": {}, # {filename: (annotations, totalSeconds)}
|
| 43 |
"speakerRenames": {}, # {filename: {speaker: name}}
|
| 44 |
"summaries": {}, # {filename: {df2, df3, ...}}
|
| 45 |
-
"categories": [],
|
| 46 |
-
"categorySelect":
|
| 47 |
"removeCategory": None,
|
| 48 |
"resetResult": False,
|
| 49 |
"unusedSpeakers": {}, # {filename: [speaker, ...]}
|
|
@@ -90,149 +91,194 @@ def convert_df(df):
|
|
| 90 |
# ---------------------------------------------------------------------------
|
| 91 |
|
| 92 |
def addCategory():
|
| 93 |
-
new = st.session_state.categoryInput
|
|
|
|
|
|
|
| 94 |
st.toast(f"Adding {new}")
|
| 95 |
-
st.session_state[f"multiselect_{new}"] = []
|
| 96 |
st.session_state.categories.append(new)
|
|
|
|
|
|
|
| 97 |
st.session_state.categoryInput = ""
|
| 98 |
-
for fname in st.session_state.categorySelect:
|
| 99 |
-
st.session_state.categorySelect[fname].append([])
|
| 100 |
|
| 101 |
|
| 102 |
def removeCategory(index):
|
| 103 |
name = st.session_state.categories[index]
|
| 104 |
st.toast(f"Removing {name}")
|
| 105 |
-
|
| 106 |
-
del st.session_state[f"remove_{name}"]
|
| 107 |
del st.session_state.categories[index]
|
| 108 |
-
|
| 109 |
-
del st.session_state.categorySelect[fname][index]
|
| 110 |
|
| 111 |
|
| 112 |
-
def updateCategoryOptions(
|
|
|
|
| 113 |
if st.session_state.resetResult:
|
| 114 |
return
|
| 115 |
-
|
| 116 |
-
speakerNames = list(currAnnotation.labels())
|
| 117 |
-
saved_renames = st.session_state.speakerRenames.get(fileName, {})
|
| 118 |
-
display_to_raw = {saved_renames.get(sp, sp): sp for sp in speakerNames}
|
| 119 |
-
unusedSpeakers = copy.deepcopy(speakerNames)
|
| 120 |
for i, category in enumerate(st.session_state.categories):
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
|
| 132 |
# ---------------------------------------------------------------------------
|
| 133 |
# Global rename callbacks
|
| 134 |
# ---------------------------------------------------------------------------
|
| 135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
def _global_rename_key(index):
|
| 137 |
return f"grename_speakers_{index}"
|
| 138 |
|
| 139 |
|
| 140 |
-
def
|
| 141 |
-
"""
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
for entry in st.session_state.globalRenames:
|
| 145 |
-
display_name = entry["name"]
|
| 146 |
-
for token in entry["speakers"]:
|
| 147 |
-
if ": " not in token:
|
| 148 |
-
continue
|
| 149 |
-
fname, raw_sp = token.split(": ", 1)
|
| 150 |
-
if fname in st.session_state.speakerRenames:
|
| 151 |
-
st.session_state.speakerRenames[fname][raw_sp] = display_name
|
| 152 |
-
curr = st.session_state.get("select_currFile")
|
| 153 |
-
if curr and curr in st.session_state.speakerRenames:
|
| 154 |
-
saved = st.session_state.speakerRenames[curr]
|
| 155 |
-
results = st.session_state.results.get(curr)
|
| 156 |
-
if results:
|
| 157 |
-
for sp in results[0].labels():
|
| 158 |
-
st.session_state[f"rename_{curr}_{sp}"] = saved.get(sp, "")
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
def enforceGlobalRenameExclusivity(changed_idx):
|
| 162 |
-
"""Ensure a token assigned to entry[changed_idx] is removed from all others.
|
| 163 |
-
|
| 164 |
-
Called by the sidebar multiselect on_change so that picking a speaker for
|
| 165 |
-
one name automatically unassigns it from any previously-holding name.
|
| 166 |
-
We pop (not overwrite) stale widget keys to avoid the Streamlit
|
| 167 |
-
"cannot modify after instantiation" error.
|
| 168 |
"""
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
|
| 179 |
|
| 180 |
def addGlobalRename():
|
| 181 |
new_name = st.session_state.globalRenameInput.strip()
|
| 182 |
if not new_name:
|
| 183 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
st.toast(f"Adding rename '{new_name}'")
|
| 185 |
st.session_state.globalRenames.append({"name": new_name, "speakers": []})
|
| 186 |
-
st.session_state[_global_rename_key(len(st.session_state.globalRenames) - 1)] = []
|
| 187 |
st.session_state.globalRenameInput = ""
|
| 188 |
|
| 189 |
|
| 190 |
def removeGlobalRename(index):
|
| 191 |
entry = st.session_state.globalRenames[index]
|
| 192 |
st.toast(f"Removing rename '{entry['name']}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
del st.session_state.globalRenames[index]
|
|
|
|
| 194 |
for i in range(index, len(st.session_state.globalRenames)):
|
| 195 |
st.session_state[_global_rename_key(i)] = list(
|
| 196 |
st.session_state.globalRenames[i]["speakers"]
|
| 197 |
)
|
| 198 |
-
applyGlobalRenames()
|
| 199 |
|
| 200 |
|
| 201 |
def apply_inline_rename(currFile, raw_sp, new_name):
|
| 202 |
-
"""Write a
|
| 203 |
-
|
| 204 |
-
Keeps the sidebar global-rename list in sync so applyGlobalRenames()
|
| 205 |
-
won't overwrite the change on the next rerun.
|
| 206 |
-
"""
|
| 207 |
new_name = new_name.strip()
|
| 208 |
token = f"{currFile}: {raw_sp}"
|
| 209 |
|
| 210 |
-
# Always remove this token from every existing entry first so it can't
|
| 211 |
-
# be claimed by more than one name at the same time.
|
| 212 |
-
# We delete the widget key (rather than overwriting it) to avoid the
|
| 213 |
-
# Streamlit "cannot modify after widget is instantiated" error β the
|
| 214 |
-
# render loop will reseed it from globalRenames data on the next rerun.
|
| 215 |
for idx, entry in enumerate(st.session_state.globalRenames):
|
| 216 |
if token in entry["speakers"]:
|
| 217 |
entry["speakers"].remove(token)
|
| 218 |
st.session_state.pop(_global_rename_key(idx), None)
|
| 219 |
|
| 220 |
if new_name:
|
| 221 |
-
|
| 222 |
-
st.session_state.speakerRenames.setdefault(currFile, {})[raw_sp] = new_name
|
| 223 |
-
# Find an existing globalRenames entry for this name, or create one
|
| 224 |
for idx, entry in enumerate(st.session_state.globalRenames):
|
| 225 |
if entry["name"] == new_name:
|
| 226 |
entry["speakers"].append(token)
|
| 227 |
st.session_state.pop(_global_rename_key(idx), None)
|
| 228 |
return
|
| 229 |
-
# No existing entry β create a new one
|
| 230 |
-
idx = len(st.session_state.globalRenames)
|
| 231 |
st.session_state.globalRenames.append({"name": new_name, "speakers": [token]})
|
| 232 |
-
# Don't pre-set the widget key here β render loop will seed it
|
| 233 |
else:
|
| 234 |
-
|
| 235 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
|
| 237 |
|
| 238 |
# ---------------------------------------------------------------------------
|
|
@@ -245,19 +291,12 @@ def updateMultiSelect():
|
|
| 245 |
result = st.session_state.results.get(fileName)
|
| 246 |
if not result:
|
| 247 |
return
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
for
|
| 253 |
-
|
| 254 |
-
st.session_state[f"rename_{fileName}_{sp}"] = saved
|
| 255 |
-
raw_to_display[sp] = saved if saved else sp
|
| 256 |
-
for i, category in enumerate(st.session_state.categories):
|
| 257 |
-
raw_choices = st.session_state.categorySelect[fileName][i]
|
| 258 |
-
st.session_state[f"multiselect_{category}"] = [
|
| 259 |
-
raw_to_display.get(sp, sp) for sp in raw_choices
|
| 260 |
-
]
|
| 261 |
|
| 262 |
|
| 263 |
# ---------------------------------------------------------------------------
|
|
@@ -294,9 +333,9 @@ def register_file(fname):
|
|
| 294 |
st.session_state.results.setdefault(fname, [])
|
| 295 |
st.session_state.summaries.setdefault(fname, {})
|
| 296 |
st.session_state.unusedSpeakers.setdefault(fname, [])
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
st.session_state.speakerRenames.setdefault(fname, {})
|
| 301 |
st.session_state.speakerClips.setdefault(fname, {})
|
| 302 |
if fname not in st.session_state.file_names:
|
|
@@ -437,7 +476,12 @@ def analyze(inFileName):
|
|
| 437 |
|
| 438 |
currAnnotation, currTotalTime = st.session_state.results[inFileName]
|
| 439 |
speakerNames = currAnnotation.labels()
|
| 440 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
printV("Loaded results", 4)
|
| 442 |
|
| 443 |
noVoice, oneVoice, multiVoice = su.calcSpeakingTypes(currAnnotation, currTotalTime)
|
|
|
|
| 5 |
- init_session_state()
|
| 6 |
- Speaker rename helpers (get_display_name, apply_speaker_renames_to_df)
|
| 7 |
- Category callbacks (addCategory, removeCategory, updateCategoryOptions)
|
| 8 |
+
- Global rename callbacks (addGlobalRename, removeGlobalRename, on_grename_change,
|
| 9 |
+
apply_inline_rename)
|
| 10 |
- File-switch callback (updateMultiSelect)
|
| 11 |
- analyze() β builds and caches all DataFrames for a single file
|
| 12 |
- convert_df(), printV()
|
|
|
|
| 43 |
"results": {}, # {filename: (annotations, totalSeconds)}
|
| 44 |
"speakerRenames": {}, # {filename: {speaker: name}}
|
| 45 |
"summaries": {}, # {filename: {df2, df3, ...}}
|
| 46 |
+
"categories": ["Instructor", "Students"],
|
| 47 |
+
"categorySelect": [[], []], # [[token, ...], ...] one list per category, tokens = "fname: SPEAKER_##"; starts with 2 lists for Instructor/Students
|
| 48 |
"removeCategory": None,
|
| 49 |
"resetResult": False,
|
| 50 |
"unusedSpeakers": {}, # {filename: [speaker, ...]}
|
|
|
|
| 91 |
# ---------------------------------------------------------------------------
|
| 92 |
|
| 93 |
def addCategory():
|
| 94 |
+
new = st.session_state.categoryInput.strip()
|
| 95 |
+
if not new:
|
| 96 |
+
return
|
| 97 |
st.toast(f"Adding {new}")
|
|
|
|
| 98 |
st.session_state.categories.append(new)
|
| 99 |
+
st.session_state.categorySelect.append([])
|
| 100 |
+
st.session_state.pop(f"multiselect_{new}", None)
|
| 101 |
st.session_state.categoryInput = ""
|
|
|
|
|
|
|
| 102 |
|
| 103 |
|
| 104 |
def removeCategory(index):
|
| 105 |
name = st.session_state.categories[index]
|
| 106 |
st.toast(f"Removing {name}")
|
| 107 |
+
st.session_state.pop(f"multiselect_{name}", None)
|
|
|
|
| 108 |
del st.session_state.categories[index]
|
| 109 |
+
del st.session_state.categorySelect[index]
|
|
|
|
| 110 |
|
| 111 |
|
| 112 |
+
def updateCategoryOptions():
|
| 113 |
+
"""Store tokens ('fname: SPEAKER_##') in the global categorySelect lists."""
|
| 114 |
if st.session_state.resetResult:
|
| 115 |
return
|
| 116 |
+
# Rebuild unusedSpeakers for every analyzed file based on current token assignments
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
for i, category in enumerate(st.session_state.categories):
|
| 118 |
+
st.session_state.categorySelect[i] = list(
|
| 119 |
+
st.session_state[f"multiselect_{category}"]
|
| 120 |
+
)
|
| 121 |
+
# Recompute unusedSpeakers for all files
|
| 122 |
+
all_assigned_tokens = {
|
| 123 |
+
token
|
| 124 |
+
for tokens in st.session_state.categorySelect
|
| 125 |
+
for token in tokens
|
| 126 |
+
}
|
| 127 |
+
for fname, result in st.session_state.results.items():
|
| 128 |
+
if len(result) != 2:
|
| 129 |
+
continue
|
| 130 |
+
annotation, _ = result
|
| 131 |
+
unused = [
|
| 132 |
+
sp for sp in annotation.labels()
|
| 133 |
+
if f"{fname}: {sp}" not in all_assigned_tokens
|
| 134 |
+
]
|
| 135 |
+
st.session_state.unusedSpeakers[fname] = unused
|
| 136 |
|
| 137 |
|
| 138 |
# ---------------------------------------------------------------------------
|
| 139 |
# Global rename callbacks
|
| 140 |
# ---------------------------------------------------------------------------
|
| 141 |
|
| 142 |
+
# ---------------------------------------------------------------------------
|
| 143 |
+
# Global rename helpers
|
| 144 |
+
# ---------------------------------------------------------------------------
|
| 145 |
+
|
| 146 |
def _global_rename_key(index):
|
| 147 |
return f"grename_speakers_{index}"
|
| 148 |
|
| 149 |
|
| 150 |
+
def _write_rename(token, name):
|
| 151 |
+
"""Write name into speakerRenames for a single token (fname: SPEAKER_##).
|
| 152 |
+
If name is empty, clears the entry (revert to raw label).
|
| 153 |
+
Silently ignores tokens that don't match a known file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
"""
|
| 155 |
+
if ": " not in token:
|
| 156 |
+
return
|
| 157 |
+
fname, raw_sp = token.split(": ", 1)
|
| 158 |
+
if fname not in st.session_state.speakerRenames:
|
| 159 |
+
return # token references an unknown file β ignore
|
| 160 |
+
if name:
|
| 161 |
+
st.session_state.speakerRenames[fname][raw_sp] = name
|
| 162 |
+
else:
|
| 163 |
+
st.session_state.speakerRenames[fname].pop(raw_sp, None)
|
| 164 |
|
| 165 |
|
| 166 |
def addGlobalRename():
|
| 167 |
new_name = st.session_state.globalRenameInput.strip()
|
| 168 |
if not new_name:
|
| 169 |
return
|
| 170 |
+
for entry in st.session_state.globalRenames:
|
| 171 |
+
if entry["name"] == new_name:
|
| 172 |
+
st.toast(f"'{new_name}' already exists in the rename list")
|
| 173 |
+
st.session_state.globalRenameInput = ""
|
| 174 |
+
return
|
| 175 |
st.toast(f"Adding rename '{new_name}'")
|
| 176 |
st.session_state.globalRenames.append({"name": new_name, "speakers": []})
|
|
|
|
| 177 |
st.session_state.globalRenameInput = ""
|
| 178 |
|
| 179 |
|
| 180 |
def removeGlobalRename(index):
|
| 181 |
entry = st.session_state.globalRenames[index]
|
| 182 |
st.toast(f"Removing rename '{entry['name']}'")
|
| 183 |
+
# Revert every speaker that belonged to this entry
|
| 184 |
+
for token in entry["speakers"]:
|
| 185 |
+
_write_rename(token, "")
|
| 186 |
+
st.session_state.pop(_global_rename_key(index), None)
|
| 187 |
del st.session_state.globalRenames[index]
|
| 188 |
+
# Shift remaining widget keys down
|
| 189 |
for i in range(index, len(st.session_state.globalRenames)):
|
| 190 |
st.session_state[_global_rename_key(i)] = list(
|
| 191 |
st.session_state.globalRenames[i]["speakers"]
|
| 192 |
)
|
|
|
|
| 193 |
|
| 194 |
|
| 195 |
def apply_inline_rename(currFile, raw_sp, new_name):
|
| 196 |
+
"""Write a rename from the Rename Speaker tab into speakerRenames and globalRenames."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
new_name = new_name.strip()
|
| 198 |
token = f"{currFile}: {raw_sp}"
|
| 199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
for idx, entry in enumerate(st.session_state.globalRenames):
|
| 201 |
if token in entry["speakers"]:
|
| 202 |
entry["speakers"].remove(token)
|
| 203 |
st.session_state.pop(_global_rename_key(idx), None)
|
| 204 |
|
| 205 |
if new_name:
|
| 206 |
+
_write_rename(token, new_name)
|
|
|
|
|
|
|
| 207 |
for idx, entry in enumerate(st.session_state.globalRenames):
|
| 208 |
if entry["name"] == new_name:
|
| 209 |
entry["speakers"].append(token)
|
| 210 |
st.session_state.pop(_global_rename_key(idx), None)
|
| 211 |
return
|
|
|
|
|
|
|
| 212 |
st.session_state.globalRenames.append({"name": new_name, "speakers": [token]})
|
|
|
|
| 213 |
else:
|
| 214 |
+
_write_rename(token, "")
|
| 215 |
+
st.toast(f"Reverted {raw_sp} to original label")
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def on_grename_change(idx):
|
| 219 |
+
"""Callback for the sidebar rename multiselect at position idx.
|
| 220 |
+
|
| 221 |
+
Diffs old vs new speakers list:
|
| 222 |
+
- Newly added tokens β enforce exclusivity, write name into speakerRenames.
|
| 223 |
+
- Removed tokens β revert speakerRenames for those tokens.
|
| 224 |
+
|
| 225 |
+
Spurious-callback guard: Streamlit sometimes re-fires this callback with an
|
| 226 |
+
empty widget value when available_tokens changes (e.g. another entry just
|
| 227 |
+
claimed a token, shrinking options). We detect this by checking whether the
|
| 228 |
+
widget value went to empty while the data model still has speakers β if ALL
|
| 229 |
+
of the previous speakers are still valid options for this entry we treat the
|
| 230 |
+
empty report as a Streamlit glitch and restore the widget key from the data
|
| 231 |
+
model instead of acting on it.
|
| 232 |
+
"""
|
| 233 |
+
grkey = _global_rename_key(idx)
|
| 234 |
+
entry = st.session_state.globalRenames[idx]
|
| 235 |
+
name = entry["name"]
|
| 236 |
+
|
| 237 |
+
prev = list(entry["speakers"]) # current data-model state (ordered)
|
| 238 |
+
reported = list(st.session_state.get(grkey, []))
|
| 239 |
+
|
| 240 |
+
# Build the set of tokens that are legitimately available for this entry
|
| 241 |
+
# right now (not claimed by any OTHER entry).
|
| 242 |
+
other_claimed = {
|
| 243 |
+
t
|
| 244 |
+
for other_idx, other_entry in enumerate(st.session_state.globalRenames)
|
| 245 |
+
if other_idx != idx
|
| 246 |
+
for t in other_entry["speakers"]
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
# Spurious-empty guard: if the widget reports [] but the data model has
|
| 250 |
+
# tokens and every one of them is still a valid (unclaimed) option, this is
|
| 251 |
+
# a Streamlit re-fire artefact β restore the key and do nothing.
|
| 252 |
+
if not reported and prev:
|
| 253 |
+
all_still_valid = all(t not in other_claimed for t in prev)
|
| 254 |
+
if all_still_valid:
|
| 255 |
+
st.session_state[grkey] = prev
|
| 256 |
+
return
|
| 257 |
+
|
| 258 |
+
prev_set = set(prev)
|
| 259 |
+
new_set = set(reported)
|
| 260 |
+
added = new_set - prev_set
|
| 261 |
+
removed = prev_set - new_set
|
| 262 |
+
|
| 263 |
+
# Write the new speakers list to the data model
|
| 264 |
+
kept = [t for t in prev if t in new_set]
|
| 265 |
+
entry["speakers"] = kept + [t for t in added]
|
| 266 |
+
st.session_state.pop(grkey, None)
|
| 267 |
+
|
| 268 |
+
# Enforce exclusivity and write renames for newly added tokens
|
| 269 |
+
for token in added:
|
| 270 |
+
for other_idx, other_entry in enumerate(st.session_state.globalRenames):
|
| 271 |
+
if other_idx == idx:
|
| 272 |
+
continue
|
| 273 |
+
if token in other_entry["speakers"]:
|
| 274 |
+
other_entry["speakers"].remove(token)
|
| 275 |
+
st.session_state.pop(_global_rename_key(other_idx), None)
|
| 276 |
+
_write_rename(token, "")
|
| 277 |
+
_write_rename(token, name)
|
| 278 |
+
|
| 279 |
+
# Revert speakerRenames for tokens genuinely removed from this entry
|
| 280 |
+
for token in removed:
|
| 281 |
+
_write_rename(token, "")
|
| 282 |
|
| 283 |
|
| 284 |
# ---------------------------------------------------------------------------
|
|
|
|
| 291 |
result = st.session_state.results.get(fileName)
|
| 292 |
if not result:
|
| 293 |
return
|
| 294 |
+
# Pop category widget keys so they re-seed from categorySelect data
|
| 295 |
+
for category in st.session_state.categories:
|
| 296 |
+
st.session_state.pop(f"multiselect_{category}", None)
|
| 297 |
+
# Pop globalRenames widget keys so they re-seed from entry["speakers"] data
|
| 298 |
+
for i in range(len(st.session_state.globalRenames)):
|
| 299 |
+
st.session_state.pop(_global_rename_key(i), None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
|
| 301 |
|
| 302 |
# ---------------------------------------------------------------------------
|
|
|
|
| 333 |
st.session_state.results.setdefault(fname, [])
|
| 334 |
st.session_state.summaries.setdefault(fname, {})
|
| 335 |
st.session_state.unusedSpeakers.setdefault(fname, [])
|
| 336 |
+
# Ensure categorySelect has one list per category (global, not per-file)
|
| 337 |
+
while len(st.session_state.categorySelect) < len(st.session_state.categories):
|
| 338 |
+
st.session_state.categorySelect.append([])
|
| 339 |
st.session_state.speakerRenames.setdefault(fname, {})
|
| 340 |
st.session_state.speakerClips.setdefault(fname, {})
|
| 341 |
if fname not in st.session_state.file_names:
|
|
|
|
| 476 |
|
| 477 |
currAnnotation, currTotalTime = st.session_state.results[inFileName]
|
| 478 |
speakerNames = currAnnotation.labels()
|
| 479 |
+
# categorySelect is global tokens ("fname: SPEAKER_##"); extract raw IDs for this file
|
| 480 |
+
prefix = inFileName + ": "
|
| 481 |
+
categorySelections = [
|
| 482 |
+
[token[len(prefix):] for token in tokens if token.startswith(prefix)]
|
| 483 |
+
for tokens in st.session_state.categorySelect
|
| 484 |
+
]
|
| 485 |
printV("Loaded results", 4)
|
| 486 |
|
| 487 |
noVoice, oneVoice, multiVoice = su.calcSpeakingTypes(currAnnotation, currTotalTime)
|