初始化
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""CPU-friendly faster-whisper entry point used by the Go media worker.
|
||||
|
||||
The process writes JSON only to stdout. Model/runtime diagnostics go to stderr so
|
||||
the Go caller never mistakes logs for transcript data.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
def configure_model_cache() -> None:
|
||||
cache_root = os.getenv("JCF_ASR_CACHE_DIR") or os.path.join(tempfile.gettempdir(), "jcf-asr-cache")
|
||||
os.makedirs(cache_root, mode=0o700, exist_ok=True)
|
||||
hf_home = os.getenv("HF_HOME") or os.path.join(cache_root, "huggingface")
|
||||
os.makedirs(hf_home, mode=0o700, exist_ok=True)
|
||||
os.environ.setdefault("XDG_CACHE_HOME", cache_root)
|
||||
os.environ.setdefault("HF_HOME", hf_home)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 2:
|
||||
print(json.dumps({"error": "missing_audio_path", "segments": []}, ensure_ascii=False))
|
||||
return 2
|
||||
|
||||
configure_model_cache()
|
||||
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
audio_path = sys.argv[1]
|
||||
language = (sys.argv[2] if len(sys.argv) > 2 else "").strip() or None
|
||||
model_name = os.getenv("FASTER_WHISPER_MODEL_PATH") or os.getenv("FASTER_WHISPER_MODEL_SIZE", "small")
|
||||
device = os.getenv("FASTER_WHISPER_DEVICE", "cpu")
|
||||
compute_type = os.getenv("FASTER_WHISPER_COMPUTE_TYPE", "int8")
|
||||
model = WhisperModel(model_name, device=device, compute_type=compute_type)
|
||||
segments, info = model.transcribe(
|
||||
audio_path,
|
||||
language=language,
|
||||
beam_size=5,
|
||||
best_of=5,
|
||||
temperature=0.0,
|
||||
condition_on_previous_text=True,
|
||||
vad_filter=True,
|
||||
vad_parameters={"min_silence_duration_ms": 700},
|
||||
word_timestamps=True,
|
||||
)
|
||||
result = []
|
||||
for segment in segments:
|
||||
text = (segment.text or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
words = []
|
||||
probabilities = []
|
||||
for word in segment.words or []:
|
||||
if word.start is None or word.end is None or not word.word:
|
||||
continue
|
||||
probability = float(word.probability) if word.probability is not None else None
|
||||
if probability is not None:
|
||||
probabilities.append(probability)
|
||||
words.append({
|
||||
"start": round(float(word.start), 3),
|
||||
"end": round(float(word.end), 3),
|
||||
"text": str(word.word),
|
||||
"probability": round(probability, 4) if probability is not None else None,
|
||||
})
|
||||
mean_probability = sum(probabilities) / len(probabilities) if probabilities else None
|
||||
avg_logprob = float(getattr(segment, "avg_logprob", -1.0) or -1.0)
|
||||
no_speech = float(getattr(segment, "no_speech_prob", 0.0) or 0.0)
|
||||
confidence = max(0.0, min(1.0, (1.0 + avg_logprob) * 0.45 + (1.0 - no_speech) * 0.2 + (mean_probability if mean_probability is not None else max(0.0, 1.0 + avg_logprob)) * 0.35))
|
||||
result.append({
|
||||
"start": round(float(segment.start), 3),
|
||||
"end": round(float(segment.end), 3),
|
||||
"text": text,
|
||||
"words": words,
|
||||
"confidence": round(confidence, 3),
|
||||
"needs_review": confidence < 0.62 or (mean_probability is not None and mean_probability < 0.55),
|
||||
})
|
||||
print(json.dumps({"language": getattr(info, "language", language), "segments": result}, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user