mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:07:04 +01:00
i3 config was filed under periodic_background, which it never was. It is now linux_configuration/i3/ (config + installer) and linux_configuration/i3blocks/ (the status scripts), both at depth 2. misc/testsAndMisc-bash/ was a directory named after the repo it already lived in, so its contents moved up to misc/. Its stray .gitignore came along, keeping the media rules working from the new location; its .vscode/tasks.json did not, because it invoked Bash/transcribe.sh, a path this repo dropped long ago. Most of this commit is the references the previous flatten missed. Its regex skipped anything with a variable prefix, which left 16 files -- including check_and_enable_services.sh and install_core_system.sh, the orchestrators -- still naming $CONFIG_DIR/scripts/periodic_background/... It had also rewritten three i3 paths into scripts/i3blocks/, a directory that has never existed; the i3blocks suites caught that by failing. 13 more symlinks broke on the i3 move. Repointed, and cpu_monitor/volume/ disk were run again to confirm the bar still reports. Depth 139 -> 104. Roughly 47 of the remainder sit in digital_wellbeing and hosts, still deferred. The rest encode real structure -- a C project, Python package directories, artgate's routes/styles, systemd unit dirs -- so flattening them further would destroy information rather than taxonomy. Verified: 1798 tests at 100%, both i3blocks suites pass, the shell coverage gate is clean, and the relocated media rules still ignore what they should while test_fw.srt stays tracked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
105 lines
3.1 KiB
Python
Executable File
105 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Resampling and cosine k-means, the maths behind speaker labelling.
|
|
|
|
numpy is fetched through ``_try_import`` rather than imported at module
|
|
scope, so this file remains importable on a machine without it - which is
|
|
what lets the transcribe tools be unit-tested in CI.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from _transcribe_media import _try_import
|
|
|
|
if TYPE_CHECKING:
|
|
import types
|
|
|
|
import numpy as np
|
|
import numpy.typing as npt
|
|
|
|
_NDIM_2D = 2
|
|
|
|
|
|
def _resample_linear(
|
|
x: npt.NDArray[np.float32],
|
|
src_sr: int,
|
|
tgt_sr: int,
|
|
) -> npt.NDArray[np.float32]:
|
|
"""Linearly resample 1-D audio array."""
|
|
np_mod = _try_import("numpy")
|
|
if np_mod is None:
|
|
msg = "numpy is required for resampling"
|
|
raise RuntimeError(msg)
|
|
|
|
if src_sr == tgt_sr:
|
|
return x
|
|
ratio = float(tgt_sr) / float(src_sr)
|
|
n_out = max(1, round(x.shape[-1] * ratio))
|
|
xp = np_mod.linspace(0.0, 1.0, num=x.shape[-1], endpoint=False)
|
|
xq = np_mod.linspace(0.0, 1.0, num=n_out, endpoint=False)
|
|
y = np_mod.interp(xq, xp, x.astype(np_mod.float32))
|
|
return y.astype(np_mod.float32)
|
|
|
|
|
|
def _kmeans_cosine(
|
|
embs: list[Any],
|
|
k: int,
|
|
iters: int = 50,
|
|
seed: int = 0,
|
|
) -> npt.NDArray[np.int64]:
|
|
"""Cluster embeddings with cosine-similarity k-means."""
|
|
np_mod = _try_import("numpy")
|
|
if np_mod is None:
|
|
msg = "numpy is required for clustering"
|
|
raise RuntimeError(msg)
|
|
|
|
rng = np_mod.random.default_rng(seed)
|
|
features = np_mod.asarray(embs, dtype=np_mod.float32)
|
|
if features.ndim != _NDIM_2D or features.shape[0] == 0:
|
|
return np_mod.zeros((0,), dtype=np_mod.int64)
|
|
features = features / (np_mod.linalg.norm(features, axis=1, keepdims=True) + 1e-8)
|
|
idxs = rng.choice(
|
|
features.shape[0],
|
|
size=min(k, features.shape[0]),
|
|
replace=False,
|
|
)
|
|
centroids = features[idxs]
|
|
if centroids.shape[0] < k:
|
|
pad = rng.standard_normal(
|
|
size=(
|
|
k - centroids.shape[0],
|
|
features.shape[1],
|
|
)
|
|
).astype(np_mod.float32)
|
|
pad /= np_mod.linalg.norm(pad, axis=1, keepdims=True) + 1e-8
|
|
centroids = np_mod.concatenate([centroids, pad], axis=0)
|
|
return _run_kmeans_iterations(np_mod, features, centroids, k, iters)
|
|
|
|
|
|
def _run_kmeans_iterations(
|
|
np_mod: types.ModuleType,
|
|
features: npt.NDArray[np.float32],
|
|
centroids: npt.NDArray[np.float32],
|
|
k: int,
|
|
iters: int,
|
|
) -> npt.NDArray[np.intp]:
|
|
"""Run k-means iteration loop and return labels."""
|
|
labels: Any = None
|
|
for _ in range(iters):
|
|
sims = features @ centroids.T
|
|
labels = sims.argmax(axis=1)
|
|
new_c = np_mod.zeros_like(centroids)
|
|
for j in range(k):
|
|
sel = features[labels == j]
|
|
if sel.shape[0] == 0:
|
|
new_c[j] = centroids[j]
|
|
else:
|
|
v = sel.mean(axis=0)
|
|
v /= np_mod.linalg.norm(v) + 1e-8
|
|
new_c[j] = v
|
|
if np_mod.allclose(new_c, centroids, atol=1e-4):
|
|
break
|
|
centroids = new_c
|
|
return labels
|