{"record":{"id":"bece5b3e881f9f82","repo":"mudler/LocalAI","slug":"analyze-head-failed-to-load-install-transformers","errorCode":null,"errorMessage":"analyze head failed to load — install transformers + torch or pass age_gender_model/emotion_model options","messagePattern":"analyze head failed to load — install transformers \\+ torch or pass age_gender_model/emotion_model options","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"backend/python/speaker-recognition/engines.py","lineNumber":288,"sourceCode":"\n    def embed(self, audio_path: str) -> list[float]:\n        waveform = self._load_waveform(audio_path)\n        vec = self._model.encode_batch(waveform).squeeze().detach().cpu().numpy()\n        return [float(x) for x in vec]\n\n    def compare(self, audio1: str, audio2: str) -> float:\n        return _cosine_distance(self.embed(audio1), self.embed(audio2))\n\n    def analyze(self, audio_path: str, actions):\n        # Age / gender / emotion aren't produced by ECAPA-TDNN itself;\n        # delegate to AnalysisHead which wraps separate Apache-2.0\n        # checkpoints. Returns a single segment spanning the clip —\n        # segmentation / diarisation is a future enhancement.\n        waveform = self._load_waveform(audio_path)\n        mono = waveform.squeeze().detach().cpu().numpy()\n        attrs = self._analysis.analyze(audio_path, mono, actions)\n        if not attrs:\n            raise NotImplementedError(\n                \"analyze head failed to load — install transformers + torch or pass age_gender_model/emotion_model options\"\n            )\n        duration = float(mono.shape[-1]) / 16000.0 if mono.size else 0.0\n        return [dict(start=0.0, end=duration, **attrs)]\n\n\nclass OnnxDirectEngine:\n    \"\"\"Run a pre-exported ONNX speaker encoder (WeSpeaker / 3D-Speaker).\"\"\"\n\n    name = \"onnx-direct\"\n\n    def __init__(self, model_name: str, options: dict[str, str]):\n        import onnxruntime as ort  # type: ignore\n\n        # The gallery is expected to have dropped the ONNX file under\n        # the models directory; accept either an absolute path or a\n        # filename relative to _model_path.\n        onnx_path = options.get(\"model_path\") or options.get(\"onnx\")","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/backend/python/speaker-recognition/engines.py#L270-L306","documentation":"Raised by the speaker-recognition backend's analyze() when the AnalysisHead (age/gender/emotion models) failed to initialize and returns no attributes for the requested actions. ECAPA-TDNN itself does not produce these outputs, so they are delegated to a separate head that requires transformers + torch and explicit model options.","triggerScenarios":"Calling analyze with actions like ['age','gender','emotion'] when transformers or torch is not installed in the backend environment, or when neither age_gender_model nor emotion_model options were provided so self._analysis has no loaded head.","commonSituations":"Minimal installs of the speaker-recognition backend without the extra analysis dependencies, or gallery configs that only specify the speaker-embedding model but request analysis actions.","solutions":["pip install transformers torch into the backend environment (or rebuild the backend image with them)","Set age_gender_model and emotion_model options in the model config pointing at the analysis checkpoints","If you only need speaker embeddings, drop age/gender/emotion from the requested actions"],"exampleFix":"# before\nresult = engine.analyze('/tmp/a.wav', ['age', 'emotion'])  # NotImplementedError\n\n# after (install deps + configure models)\n# pip install transformers torch\nengine = EcapaTdnnEngine(name, {'age_gender_model': '/models/ag.onnx', 'emotion_model': '/models/em.onnx', ...})","handlingStrategy":"try-catch","validationCode":"def can_analyze(engine, actions) -> bool:\n    if not {'age', 'gender', 'emotion'} & set(actions):\n        return True  # embedding-only path is fine\n    return getattr(engine, '_analysis', None) is not None and engine._analysis.loaded","typeGuard":"def analysis_ready(engine) -> bool:\n    head = getattr(engine, '_analysis', None)\n    return head is not None and getattr(head, 'loaded', False)","tryCatchPattern":"try:\n    segments = engine.analyze(path, actions)\nexcept NotImplementedError as err:\n    # capability gap: install transformers+torch and configure analysis models\n    return error_response(str(err), hint='analysis requires extra models/deps')","preventionTips":["Install transformers and torch in the backend environment","Configure age_gender_model/emotion_model options when analysis is needed","Request only the actions your deployment actually supports"],"tags":["python","speaker-recognition","missing-dependency","audio"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}