Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ after its first published distribution.
heads, combining only the targets each sample actually carries.
- Internal hierarchical utterance sampling primitives: square-root corpus mass,
inverse-square-root class mass, and bounded seeded window selection.
- Feature backends resolve and expose the exact model revision they loaded, and
accept a `repository@revision` model identifier to pin it.

### Changed

Expand Down
24 changes: 24 additions & 0 deletions ser/_internal/repr/emotion2vec.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import hashlib
import importlib
import importlib.util
import logging
Expand Down Expand Up @@ -157,6 +158,29 @@ def backend_id(self) -> str:
"""Stable backend identifier used by runtime capability registry."""
return "emotion2vec"

@property
def model_revision(self) -> str | None:
"""Returns an exact hub commit when exposed by the loaded backend."""
if self._model is not None:
revision = getattr(self._model.config, "_commit_hash", None)
if isinstance(revision, str) and revision.strip():
return revision.strip()
source, is_local = self._resolve_funasr_model_source()
source_path = Path(source)
if not is_local or not source_path.is_dir():
return None
digest = hashlib.sha256()
for path in sorted(
source_path.rglob("*"), key=lambda item: str(item.relative_to(source_path))
):
if not path.is_file():
continue
digest.update(str(path.relative_to(source_path)).encode("utf-8"))
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return f"content-sha256:{digest.hexdigest()}"

@property
def feature_dim(self) -> int:
"""Returns dynamic embedding size from model configuration."""
Expand Down
17 changes: 16 additions & 1 deletion ser/_internal/repr/hf_whisper.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,13 @@ def __init__(
raise ValueError(
"feature_extractor and model must be provided together or omitted together."
)
self._model_id = model_id
self._model_id, separator, requested_revision = model_id.rpartition("@")
if not separator:
self._model_id = model_id
requested_revision = ""
if not self._model_id:
raise ValueError("model_id repository must be non-empty.")
self._requested_revision = requested_revision or None
self._max_chunk_seconds = max_chunk_seconds
self._cache_dir = cache_dir
self._device = device
Expand All @@ -151,6 +157,13 @@ def backend_id(self) -> str:
"""Stable backend identifier used by runtime capability registry."""
return "hf_whisper"

@property
def model_revision(self) -> str | None:
"""Returns the exact Hugging Face commit resolved by the loaded model."""
_, model = self._ensure_runtime_components()
revision = getattr(model.config, "_commit_hash", None)
return revision.strip() if isinstance(revision, str) and revision.strip() else None

@property
def feature_dim(self) -> int:
"""Returns dynamic embedding size from model configuration."""
Expand Down Expand Up @@ -328,6 +341,8 @@ def _ensure_runtime_components(self) -> tuple[_FeatureExtractor, _EncoderModel]:
if self._cache_dir is not None:
self._cache_dir.mkdir(parents=True, exist_ok=True)
cache_kwargs["cache_dir"] = str(self._cache_dir)
if self._requested_revision is not None:
cache_kwargs["revision"] = self._requested_revision

feature_extractor = cast(
_FeatureExtractor,
Expand Down
17 changes: 16 additions & 1 deletion ser/_internal/repr/hf_xlsr.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ def __init__(
raise ValueError(
"feature_extractor and model must be provided together or omitted together."
)
self._model_id = model_id
self._model_id, separator, requested_revision = model_id.rpartition("@")
if not separator:
self._model_id = model_id
requested_revision = ""
if not self._model_id:
raise ValueError("model_id repository must be non-empty.")
self._requested_revision = requested_revision or None
self._max_chunk_seconds = max_chunk_seconds
self._cache_dir = cache_dir
self._device = device
Expand All @@ -131,6 +137,13 @@ def backend_id(self) -> str:
"""Stable backend identifier used by runtime capability registry."""
return "hf_xlsr"

@property
def model_revision(self) -> str | None:
"""Returns the exact Hugging Face commit resolved by the loaded model."""
_, model = self._ensure_runtime_components()
revision = getattr(model.config, "_commit_hash", None)
return revision.strip() if isinstance(revision, str) and revision.strip() else None

@property
def feature_dim(self) -> int:
"""Returns dynamic embedding size from model configuration."""
Expand Down Expand Up @@ -307,6 +320,8 @@ def _ensure_runtime_components(self) -> tuple[_FeatureExtractor, _EncoderModel]:
if self._cache_dir is not None:
self._cache_dir.mkdir(parents=True, exist_ok=True)
cache_kwargs["cache_dir"] = str(self._cache_dir)
if self._requested_revision is not None:
cache_kwargs["revision"] = self._requested_revision

feature_extractor = cast(
_FeatureExtractor,
Expand Down