s2t 0.1.0.post1.dev2__tar.gz → 0.1.2__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.
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/.gitignore +2 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/Makefile +10 -2
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/PKG-INFO +1 -1
- s2t-0.1.2/docs/SESSION_STATE.md +35 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/cli.py +2 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/whisper_engine.py +26 -2
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/PKG-INFO +1 -1
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/SOURCES.txt +1 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/.pre-commit-config.yaml +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/AGENTS.md +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/CONTRIBUTING.md +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/MANIFEST.in +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/README.md +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/docs/RELEASING.md +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/pyproject.toml +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/scripts/bench_transcribe.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/setup.cfg +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/__init__.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/config.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/outputs.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/py.typed +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/recorder.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/types.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t/utils.py +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/dependency_links.txt +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/entry_points.txt +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/requires.txt +0 -0
- {s2t-0.1.0.post1.dev2 → s2t-0.1.2}/src/s2t.egg-info/top_level.txt +0 -0
@@ -66,18 +66,26 @@ publish: guard-venv build
|
|
66
66
|
$(PYTHON) -c 'import importlib.util,sys; sys.exit(0) if importlib.util.find_spec("twine") else sys.exit(1)' || $(PIP) install twine ; \
|
67
67
|
[ -f .env.twine ] && set -a && . ./.env.twine && set +a || true; \
|
68
68
|
if [ "$$ALLOW_CUSTOM_TWINE_USERNAME" = "1" ]; then TWINE_USERNAME="$${TWINE_USERNAME:-__token__}"; else TWINE_USERNAME="__token__"; fi; \
|
69
|
+
# Prefer prod-specific secrets first
|
70
|
+
if [ -n "$$TWINE_PROD_PASSWORD_CMD" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(sh -c "$$TWINE_PROD_PASSWORD_CMD" | head -n1 | tr -d '\r\n')"; fi; \
|
71
|
+
if [ -n "$$PASS_PROD_TWINE_ENTRY" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(pass show "$$PASS_PROD_TWINE_ENTRY" | head -n1 | tr -d '\r\n')"; fi; \
|
72
|
+
# Fallback to generic secrets
|
69
73
|
if [ -n "$$TWINE_PASSWORD_CMD" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(sh -c "$$TWINE_PASSWORD_CMD" | head -n1 | tr -d '\r\n')"; fi; \
|
70
74
|
if [ -n "$$PASS_TWINE_ENTRY" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(pass show "$$PASS_TWINE_ENTRY" | head -n1 | tr -d '\r\n')"; fi; \
|
71
|
-
if [ -z "$$TWINE_PASSWORD" ]; then echo "Error: TWINE_PASSWORD is empty. Provide via .env.twine,
|
75
|
+
if [ -z "$$TWINE_PASSWORD" ]; then echo "Error: TWINE_PASSWORD is empty. Provide via .env.twine, TWINE_*_PASSWORD_CMD, or PASS_*_TWINE_ENTRY." >&2; exit 2; fi; \
|
72
76
|
env TWINE_USERNAME="$$TWINE_USERNAME" TWINE_PASSWORD="$$TWINE_PASSWORD" twine upload --non-interactive $$TWINE_EXTRA_FLAGS dist/*
|
73
77
|
|
74
78
|
publish-test: guard-venv build
|
75
79
|
$(PYTHON) -c 'import importlib.util,sys; sys.exit(0) if importlib.util.find_spec("twine") else sys.exit(1)' || $(PIP) install twine ; \
|
76
80
|
[ -f .env.twine ] && set -a && . ./.env.twine && set +a || true; \
|
77
81
|
if [ "$$ALLOW_CUSTOM_TWINE_USERNAME" = "1" ]; then TWINE_USERNAME="$${TWINE_USERNAME:-__token__}"; else TWINE_USERNAME="__token__"; fi; \
|
82
|
+
# Prefer test-specific secrets first
|
83
|
+
if [ -n "$$TWINE_TEST_PASSWORD_CMD" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(sh -c "$$TWINE_TEST_PASSWORD_CMD" | head -n1 | tr -d '\r\n')"; fi; \
|
84
|
+
if [ -n "$$PASS_TEST_TWINE_ENTRY" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(pass show "$$PASS_TEST_TWINE_ENTRY" | head -n1 | tr -d '\r\n')"; fi; \
|
85
|
+
# Fallback to generic secrets
|
78
86
|
if [ -n "$$TWINE_PASSWORD_CMD" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(sh -c "$$TWINE_PASSWORD_CMD" | head -n1 | tr -d '\r\n')"; fi; \
|
79
87
|
if [ -n "$$PASS_TWINE_ENTRY" ] && [ -z "$$TWINE_PASSWORD" ]; then TWINE_PASSWORD="$$(pass show "$$PASS_TWINE_ENTRY" | head -n1 | tr -d '\r\n')"; fi; \
|
80
|
-
if [ -z "$$TWINE_PASSWORD" ]; then echo "Error: TWINE_PASSWORD is empty. Provide via .env.twine,
|
88
|
+
if [ -z "$$TWINE_PASSWORD" ]; then echo "Error: TWINE_PASSWORD is empty. Provide via .env.twine, TWINE_*_PASSWORD_CMD, or PASS_*_TWINE_ENTRY." >&2; exit 2; fi; \
|
81
89
|
env TWINE_USERNAME="$$TWINE_USERNAME" TWINE_PASSWORD="$$TWINE_PASSWORD" twine upload --non-interactive --repository testpypi $$TWINE_EXTRA_FLAGS dist/*
|
82
90
|
|
83
91
|
record: guard-venv
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Session State
|
2
|
+
|
3
|
+
Stand: Deployment vorbereiten, Paket ist baubar und typgeprüft. Upload zu TestPyPI steht aus.
|
4
|
+
|
5
|
+
## Änderungen dieser Session (Kurzfassung)
|
6
|
+
- Formatter auf nur Ruff umgestellt (Black entfernt); Makefile `format`/`lint` fixen automatisch.
|
7
|
+
- mypy-Fehler streng behoben (TypedDicts in `src/s2t/types.py`).
|
8
|
+
- Drittanbieter-Stubs nach `stubs/` verschoben (`sounddevice`, `soundfile`, `pyperclip`, `whisper`).
|
9
|
+
- Paket als "typed" markiert (`src/s2t/py.typed`) und Stubs via `MANIFEST.in` vom sdist ausgeschlossen.
|
10
|
+
- pyproject: Ruff-Konfig aktualisiert, Lizenzfeld auf SPDX-Form (`LicenseRef-Proprietary`).
|
11
|
+
- Doku: README verschlankt; `CONTRIBUTING.md`, `docs/RELEASING.md` hinzugefügt. Linux Systemlibs-Hinweis ergänzt.
|
12
|
+
- Build geprüft: `make build` erzeugt gültiges Wheel + sdist; `twine check dist/*` ist grün.
|
13
|
+
|
14
|
+
## Offene Schritte (für TestPyPI/PyPI)
|
15
|
+
1) TestPyPI-Creds bereitstellen (eine der Optionen):
|
16
|
+
- `.env.twine` im Projekt (gitignored) mit:
|
17
|
+
- `TWINE_USERNAME=__token__`
|
18
|
+
- `TWINE_PASSWORD=dein_testpypi_api_token`
|
19
|
+
- oder `~/.pypirc` konfigurieren (testpypi Sektion).
|
20
|
+
2) Upload anstoßen:
|
21
|
+
- `make publish-test`
|
22
|
+
3) Installation validieren in frischem venv:
|
23
|
+
- `python -m venv .venv-test && source .venv-test/bin/activate`
|
24
|
+
- `pip install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple s2t`
|
25
|
+
- Smoke: `s2t -h`, optional `s2t -L`
|
26
|
+
4) Wenn ok: PyPI-Upload
|
27
|
+
- `make publish` (mit PyPI-Token analog zu TestPyPI)
|
28
|
+
|
29
|
+
## Hinweise
|
30
|
+
- Linux: ggf. `libportaudio2` und `libsndfile1` installieren; ffmpeg optional für MP3.
|
31
|
+
- Keine Secrets im Repo: `.env.twine` ist per `.gitignore` ausgeschlossen.
|
32
|
+
|
33
|
+
## Wiedereinstieg
|
34
|
+
- Falls `.env.twine` schon existiert: direkt `make publish-test` ausführen.
|
35
|
+
- Danach Installation wie oben testen; bei Erfolg `make publish`.
|
@@ -256,6 +256,8 @@ def run_session(opts: SessionOptions) -> int:
|
|
256
256
|
else:
|
257
257
|
print("—" * 60)
|
258
258
|
print("Transcript (clipboard text):")
|
259
|
+
# Visual separator before the actual transcript text
|
260
|
+
print("=" * 60)
|
259
261
|
print(text_final.rstrip("\n"))
|
260
262
|
|
261
263
|
if opts.profile:
|
@@ -29,7 +29,10 @@ class WhisperEngine:
|
|
29
29
|
self.samplerate = samplerate
|
30
30
|
self.channels = channels
|
31
31
|
self.verbose = verbose
|
32
|
-
|
32
|
+
# Use the provided profile dict even if it's empty.
|
33
|
+
# Using `or {}` would create a new dict when an empty one is passed,
|
34
|
+
# breaking shared accumulation with the caller (CLI).
|
35
|
+
self.profile = profile if profile is not None else {}
|
33
36
|
self._executor: ThreadPoolExecutor | None = None
|
34
37
|
|
35
38
|
def preload(self) -> tuple[ThreadPoolExecutor | None, Future | None]:
|
@@ -75,10 +78,31 @@ class WhisperEngine:
|
|
75
78
|
frames: int,
|
76
79
|
initial_prompt: str | None = None,
|
77
80
|
) -> TranscriptionResult:
|
81
|
+
# Load audio without ffmpeg by reading via soundfile and passing a numpy array
|
82
|
+
# to Whisper. We ensure mono float32 at 16 kHz as expected by Whisper's API.
|
78
83
|
task = "translate" if self.translate else "transcribe"
|
84
|
+
import numpy as np
|
85
|
+
|
86
|
+
try:
|
87
|
+
import soundfile as sf
|
88
|
+
except Exception as e:
|
89
|
+
raise RuntimeError("soundfile is required to read recorded audio.") from e
|
90
|
+
|
91
|
+
from .utils import resample_linear
|
92
|
+
|
93
|
+
# Read audio from file (supports WAV/FLAC via libsndfile), convert to mono
|
94
|
+
data, sr = sf.read(str(audio_path), dtype="float32", always_2d=True)
|
95
|
+
# data shape: (n_frames, n_channels). Convert to mono by averaging if needed
|
96
|
+
if data.ndim == 2 and data.shape[1] > 1:
|
97
|
+
mono = data.mean(axis=1)
|
98
|
+
else:
|
99
|
+
mono = data.reshape(-1)
|
100
|
+
# Resample to 16k expected by Whisper when passing arrays
|
101
|
+
mono_16k: np.ndarray = resample_linear(mono, int(sr), 16000)
|
102
|
+
|
79
103
|
t0 = time.perf_counter()
|
80
104
|
res: dict[str, Any] = model.transcribe(
|
81
|
-
|
105
|
+
mono_16k,
|
82
106
|
task=task,
|
83
107
|
language=self.language,
|
84
108
|
fp16=False,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|