speaker-detector 0.1.6__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/PKG-INFO +2 -2
  2. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/README.md +1 -1
  3. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/pyproject.toml +1 -1
  4. speaker_detector-0.1.7/speaker_detector/constants.py +10 -0
  5. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/core.py +2 -0
  6. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/server.py +23 -10
  7. speaker_detector-0.1.7/speaker_detector/speaker_state.py +103 -0
  8. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/PKG-INFO +2 -2
  9. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/SOURCES.txt +2 -1
  10. speaker_detector-0.1.6/speaker_detector/state.py +0 -69
  11. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/setup.cfg +0 -0
  12. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/__main__.py +0 -0
  13. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/cli.py +0 -0
  14. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/ECAPA_TDNN.py +0 -0
  15. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/classifier.ckpt +0 -0
  16. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/embedding_model.ckpt +0 -0
  17. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/hyperparams.yaml +0 -0
  18. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/label_encoder.ckpt +0 -0
  19. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/model/mean_var_norm_emb.ckpt +0 -0
  20. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/server copy.py +0 -0
  21. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/__init__.py +0 -0
  22. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/favicon.ico +0 -0
  23. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/index.html +0 -0
  24. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/scripts/loader copy.js +0 -0
  25. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/scripts/loader.js +0 -0
  26. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/scripts/script copy.js +0 -0
  27. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/scripts/script.js +0 -0
  28. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector/web/static/style.css +0 -0
  29. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/dependency_links.txt +0 -0
  30. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/entry_points.txt +0 -0
  31. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/requires.txt +0 -0
  32. {speaker_detector-0.1.6 → speaker_detector-0.1.7}/speaker_detector.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: speaker-detector
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A CLI + Web tool for speaker enrollment and identification using SpeechBrain.
5
5
  Author-email: Lara Whybrow <lara.whybrow@gmail.com>
6
6
  License: MIT
@@ -29,7 +29,7 @@ Requires-Dist: sounddevice
29
29
  Requires-Dist: soundfile
30
30
  Requires-Dist: pydub
31
31
 
32
- Note: Still in development, as I am configuring the system for the most performant approach. Feel free to jump on the project with me.
32
+ 23/07/2025 - Lara Whybrow, Creator - Works as far as I can see, but now we have a robust set of tools for training and managing the data and can focus now on refinement and bug fixing.
33
33
 
34
34
  # speaker-detector 🎙️
35
35
 
@@ -1,4 +1,4 @@
1
- Note: Still in development, as I am configuring the system for the most performant approach. Feel free to jump on the project with me.
1
+ 23/07/2025 - Lara Whybrow, Creator - Works as far as I can see, but now we have a robust set of tools for training and managing the data and can focus now on refinement and bug fixing.
2
2
 
3
3
  # speaker-detector 🎙️
4
4
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "speaker-detector"
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  description = "A CLI + Web tool for speaker enrollment and identification using SpeechBrain."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1,10 @@
1
+ # speaker_detector/constants.py
2
+
3
+ BACKEND_VERSION = "0.1.7"
4
+
5
+ # API base paths (optional, for future centralization)
6
+ API_PREFIX = "/api"
7
+
8
+ # Thresholds and default settings
9
+ DEFAULT_CONFIDENCE_THRESHOLD = 0.75
10
+ DEFAULT_INTERVAL_MS = 3000
@@ -114,3 +114,5 @@ def get_speakers_needing_rebuild() -> list[str]:
114
114
 
115
115
  # ── ALIAS FOR COMPATIBILITY ──────────────────────────────────────────────────
116
116
  rebuild_embeddings_for_speaker = rebuild_embedding
117
+
118
+
@@ -1,26 +1,36 @@
1
1
  # ── Core Imports ─────────────────────────────────────────────
2
2
  import os, signal, time
3
- from flask import Flask, request, send_from_directory, send_file
3
+ from flask import Flask, request, send_from_directory, send_file, jsonify
4
4
  from flask_cors import CORS
5
5
  from pathlib import Path
6
6
 
7
7
  # ── Internal Modules ─────────────────────────────────────────
8
- from speaker_detector.state import stop_event
9
8
  from speaker_detector.utils.paths import STATIC_DIR, INDEX_HTML, COMPONENTS_DIR
9
+ from speaker_detector.speaker_state import LISTENING_MODE, start_detection_loop, stop_detection_loop, stop_event
10
+ from speaker_detector.constants import BACKEND_VERSION
11
+
12
+
10
13
 
11
14
  # ── App Setup ────────────────────────────────────────────────
12
15
  app = Flask(__name__, static_folder=str(STATIC_DIR))
13
- CORS(app)
16
+ CORS(app, resources={r"/api/*": {"origins": "*"}}, supports_credentials=True)
14
17
 
15
18
 
16
19
  # ── Routes ──────────────────────────────────────────────────
17
- @app.after_request
18
- def apply_csp(response):
19
- response.headers["Content-Security-Policy"] = (
20
- "default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none';"
21
- )
20
+ @app.route("/api/<path:dummy>", methods=["OPTIONS"])
21
+ def cors_preflight(dummy):
22
+ response = jsonify({"ok": True})
23
+ response.headers["Access-Control-Allow-Origin"] = "*"
24
+ response.headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
25
+ response.headers["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"
22
26
  return response
23
27
 
28
+
29
+
30
+ @app.route("/api/version")
31
+ def get_version():
32
+ return jsonify({"version": BACKEND_VERSION})
33
+
24
34
  @app.route("/")
25
35
  def serve_index():
26
36
  return send_file(INDEX_HTML)
@@ -47,22 +57,25 @@ def not_found(e):
47
57
 
48
58
  # ── Route Registrations ─────────────────────────────────────
49
59
  from speaker_detector.routes.index_routes import index_bp
50
- from speaker_detector.routes.settings_routes import settings_bp
60
+ from speaker_detector.routes.listening_mode_routes import listening_bp
51
61
  from speaker_detector.routes.speaker_routes import speakers_bp
52
62
  from speaker_detector.routes.background_routes import background_bp
53
63
  from speaker_detector.routes.rebuild_routes import rebuild_bp
54
64
  from speaker_detector.routes.identify_routes import identify_bp
55
65
  from speaker_detector.routes.recordings_routes import recordings_bp
56
66
  from speaker_detector.routes.meetings_routes import meetings_bp
67
+ from speaker_detector.routes.correction_routes import correction_bp
68
+
57
69
 
58
70
  app.register_blueprint(index_bp)
59
- app.register_blueprint(settings_bp)
71
+ app.register_blueprint(listening_bp)
60
72
  app.register_blueprint(speakers_bp)
61
73
  app.register_blueprint(background_bp)
62
74
  app.register_blueprint(rebuild_bp)
63
75
  app.register_blueprint(identify_bp)
64
76
  app.register_blueprint(recordings_bp)
65
77
  app.register_blueprint(meetings_bp)
78
+ app.register_blueprint(correction_bp)
66
79
 
67
80
  # ── Interrupt Handler ───────────────────────────────────────
68
81
  def handle_interrupt(sig, frame):
@@ -0,0 +1,103 @@
1
+ # speaker_detector/speaker_state.py
2
+
3
+ import threading
4
+ import tempfile
5
+ import time
6
+ import sounddevice as sd
7
+ import soundfile as sf
8
+ from datetime import datetime
9
+
10
+ from speaker_detector.constants import DEFAULT_CONFIDENCE_THRESHOLD, DEFAULT_INTERVAL_MS
11
+ from speaker_detector.core import identify_speaker
12
+
13
+ # ── Shared Speaker Detection State ─────────────────────────────
14
+
15
+ current_speaker_state = {
16
+ "speaker": None,
17
+ "confidence": None,
18
+ "is_speaking": False,
19
+ }
20
+
21
+ def get_current_speaker():
22
+ return current_speaker_state
23
+
24
+ LISTENING_MODE = {"mode": "off"} # Options: "off", "single", "multi"
25
+ DETECTION_INTERVAL_MS = DEFAULT_INTERVAL_MS
26
+ DETECTION_THRESHOLD = DEFAULT_CONFIDENCE_THRESHOLD
27
+
28
+ MIC_AVAILABLE = True
29
+ stop_event = threading.Event()
30
+ detection_thread = None
31
+
32
+ # ── Background Detection Loop ─────────────────────────────
33
+
34
+ def detection_loop():
35
+ global MIC_AVAILABLE
36
+
37
+ samplerate = 16000
38
+ duration = 2 # seconds
39
+
40
+ while not stop_event.is_set():
41
+ try:
42
+ audio = sd.rec(int(duration * samplerate), samplerate=samplerate, channels=1, dtype="int16")
43
+ sd.wait()
44
+
45
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
46
+ sf.write(tmp.name, audio, samplerate)
47
+ MIC_AVAILABLE = True
48
+
49
+ speaker, conf = identify_speaker(tmp.name, threshold=DETECTION_THRESHOLD)
50
+ current_speaker_state["speaker"] = speaker
51
+ current_speaker_state["confidence"] = conf
52
+ current_speaker_state["is_speaking"] = speaker != "unknown" and conf >= DETECTION_THRESHOLD
53
+
54
+ print(f"{datetime.now().strftime('%H:%M:%S')} 🧠 Detected: {speaker} ({conf:.2f})")
55
+
56
+ except Exception as e:
57
+ print(f"❌ Detection loop error: {e}")
58
+ current_speaker_state["speaker"] = None
59
+ current_speaker_state["confidence"] = None
60
+ current_speaker_state["is_speaking"] = False
61
+ if isinstance(e, sd.PortAudioError):
62
+ MIC_AVAILABLE = False
63
+
64
+ time.sleep(DETECTION_INTERVAL_MS / 1000.0)
65
+
66
+ # ── Lifecycle Control ─────────────────────────────────────
67
+
68
+ def start_detection_loop():
69
+ global detection_thread
70
+ if detection_thread and detection_thread.is_alive():
71
+ return
72
+ print("🔁 Starting detection loop...")
73
+ stop_event.clear()
74
+ detection_thread = threading.Thread(target=detection_loop, daemon=True)
75
+ detection_thread.start()
76
+
77
+ def stop_detection_loop():
78
+ if detection_thread and detection_thread.is_alive():
79
+ print("⏹️ Stopping detection loop...")
80
+ stop_event.set()
81
+
82
+ def get_active_speaker():
83
+ if LISTENING_MODE["mode"] == "off":
84
+ return {
85
+ "speaker": None,
86
+ "confidence": None,
87
+ "is_speaking": False,
88
+ "status": "disabled"
89
+ }
90
+ if not MIC_AVAILABLE:
91
+ return {
92
+ "speaker": None,
93
+ "confidence": None,
94
+ "is_speaking": False,
95
+ "status": "mic unavailable"
96
+ }
97
+
98
+ return {
99
+ "speaker": current_speaker_state.get("speaker"),
100
+ "confidence": current_speaker_state.get("confidence"),
101
+ "is_speaking": current_speaker_state.get("is_speaking", False),
102
+ "status": "listening"
103
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: speaker-detector
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A CLI + Web tool for speaker enrollment and identification using SpeechBrain.
5
5
  Author-email: Lara Whybrow <lara.whybrow@gmail.com>
6
6
  License: MIT
@@ -29,7 +29,7 @@ Requires-Dist: sounddevice
29
29
  Requires-Dist: soundfile
30
30
  Requires-Dist: pydub
31
31
 
32
- Note: Still in development, as I am configuring the system for the most performant approach. Feel free to jump on the project with me.
32
+ 23/07/2025 - Lara Whybrow, Creator - Works as far as I can see, but now we have a robust set of tools for training and managing the data and can focus now on refinement and bug fixing.
33
33
 
34
34
  # speaker-detector 🎙️
35
35
 
@@ -2,10 +2,11 @@ README.md
2
2
  pyproject.toml
3
3
  speaker_detector/__main__.py
4
4
  speaker_detector/cli.py
5
+ speaker_detector/constants.py
5
6
  speaker_detector/core.py
6
7
  speaker_detector/server copy.py
7
8
  speaker_detector/server.py
8
- speaker_detector/state.py
9
+ speaker_detector/speaker_state.py
9
10
  speaker_detector.egg-info/PKG-INFO
10
11
  speaker_detector.egg-info/SOURCES.txt
11
12
  speaker_detector.egg-info/dependency_links.txt
@@ -1,69 +0,0 @@
1
- # speaker_detector/state.py
2
-
3
- import threading
4
- import tempfile
5
- import time
6
- import sounddevice as sd
7
- import soundfile as sf
8
- from datetime import datetime
9
- from pathlib import Path
10
-
11
- from speaker_detector.core import identify_speaker # ✅ safe import — no circular loop
12
-
13
- # ── Global State ─────────────────────────────────────────────
14
- current_speaker = {"speaker": None, "confidence": None}
15
- LISTENING_MODE = {"mode": "off"} # Values: "off", "single", "multi"
16
- DETECTION_INTERVAL_MS = 3000
17
- DETECTION_THRESHOLD = 0.75
18
-
19
- MIC_AVAILABLE = True
20
- stop_event = threading.Event() # ✅ defined here, no self-import
21
- detection_thread = None
22
-
23
- # ── Background Detection Loop ────────────────────────────────
24
- def detection_loop():
25
- global MIC_AVAILABLE
26
-
27
- samplerate = 16000
28
- duration = 2
29
-
30
- while not stop_event.is_set():
31
- try:
32
- audio = sd.rec(int(duration * samplerate), samplerate=samplerate, channels=1, dtype="int16")
33
- sd.wait()
34
-
35
- with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
36
- sf.write(tmp.name, audio, samplerate)
37
- MIC_AVAILABLE = True
38
- speaker, conf = identify_speaker(tmp.name, threshold=DETECTION_THRESHOLD)
39
- current_speaker.update(speaker=speaker, confidence=conf)
40
- print(f"{datetime.now().strftime('%H:%M:%S')} 🧠 Detected: {speaker} ({conf:.2f})")
41
- except Exception as e:
42
- print(f"❌ Detection loop error: {e}")
43
- current_speaker.update(speaker=None, confidence=None)
44
- if isinstance(e, sd.PortAudioError):
45
- MIC_AVAILABLE = False
46
-
47
- time.sleep(DETECTION_INTERVAL_MS / 1000.0)
48
-
49
- # ── Control Functions ────────────────────────────────────────
50
- def start_detection_loop():
51
- global detection_thread
52
- if detection_thread and detection_thread.is_alive():
53
- return
54
- print("🔁 Starting detection loop...")
55
- stop_event.clear()
56
- detection_thread = threading.Thread(target=detection_loop, daemon=True)
57
- detection_thread.start()
58
-
59
- def stop_detection_loop():
60
- if detection_thread and detection_thread.is_alive():
61
- print("⏹️ Stopping detection loop...")
62
- stop_event.set()
63
-
64
- def get_active_speaker():
65
- if LISTENING_MODE["mode"] == "off":
66
- return {"speaker": None, "confidence": None, "status": "disabled"}
67
- if not MIC_AVAILABLE:
68
- return {"speaker": None, "confidence": None, "status": "mic unavailable"}
69
- return {**current_speaker, "status": "listening"}