feat: full-platform STT API (v2.3 consensus plan) #1
@@ -23,6 +23,7 @@ class TranscribeOptions(BaseModel):
|
|||||||
hotwords: list[str] = Field(default_factory=list)
|
hotwords: list[str] = Field(default_factory=list)
|
||||||
vad: bool = True
|
vad: bool = True
|
||||||
glossary_id: str | None = None
|
glossary_id: str | None = None
|
||||||
|
glossary: dict[str, str] | None = None # {오인식 패턴: 표준 표기} — 후처리 glossary
|
||||||
post_correction: dict[str, Any] | None = None
|
post_correction: dict[str, Any] | None = None
|
||||||
diarize: bool = False
|
diarize: bool = False
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,11 @@ def transcribe(
|
|||||||
if "=" not in item:
|
if "=" not in item:
|
||||||
_fail(EXIT_INPUT, f"--glossary는 'KEY=VALUE' 형식이어야 합니다: {item}")
|
_fail(EXIT_INPUT, f"--glossary는 'KEY=VALUE' 형식이어야 합니다: {item}")
|
||||||
key, _, value = item.partition("=")
|
key, _, value = item.partition("=")
|
||||||
glossary_dict[key.strip()] = value.strip()
|
key, value = key.strip(), value.strip()
|
||||||
|
if not key or not value:
|
||||||
|
# 빈 패턴(re.escape(''))은 모든 위치에 매칭돼 텍스트를 망가뜨린다
|
||||||
|
_fail(EXIT_INPUT, f"--glossary 키/값이 비어 있으면 안 됩니다: {item}")
|
||||||
|
glossary_dict[key] = value
|
||||||
try:
|
try:
|
||||||
pipeline = BatchPipeline(settings=settings, token=token)
|
pipeline = BatchPipeline(settings=settings, token=token)
|
||||||
result = pipeline.run(
|
result = pipeline.run(
|
||||||
|
|||||||
@@ -110,10 +110,12 @@ class Worker:
|
|||||||
if k in TranscriptionOptions.__slots__
|
if k in TranscriptionOptions.__slots__
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# API 옵션의 glossary/post_correction(dict)을 후처리 glossary로 전달
|
# API 옵션의 glossary/post_correction(dict)을 후처리 glossary로 전달.
|
||||||
glossary = (job.options or {}).get("glossary") or (job.options or {}).get(
|
# pydantic 스키마를 거치지 않은 직접 생성 Job은 비-dict일 수 있어 방어.
|
||||||
|
raw_glossary = (job.options or {}).get("glossary") or (job.options or {}).get(
|
||||||
"post_correction"
|
"post_correction"
|
||||||
)
|
)
|
||||||
|
glossary = raw_glossary if isinstance(raw_glossary, dict) else None
|
||||||
result = pipeline.run(job, options, progress_cb=progress_cb, glossary=glossary)
|
result = pipeline.run(job, options, progress_cb=progress_cb, glossary=glossary)
|
||||||
# 결과를 먼저 영속화한 뒤 상태 전이 (실패 시 FAILED로 전이 가능하게)
|
# 결과를 먼저 영속화한 뒤 상태 전이 (실패 시 FAILED로 전이 가능하게)
|
||||||
self.store.write_result(job.id, result)
|
self.store.write_result(job.id, result)
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ from ..results.models import Segment
|
|||||||
DEFAULT_RULES: list[tuple[re.Pattern, str]] = [
|
DEFAULT_RULES: list[tuple[re.Pattern, str]] = [
|
||||||
(re.compile(r"\bv ?l ?l ?m\b", re.IGNORECASE), "vLLM"),
|
(re.compile(r"\bv ?l ?l ?m\b", re.IGNORECASE), "vLLM"),
|
||||||
# 흔한 오인식: vLLM → BLM (GPU 실전에서 재현). 기술 STT 도메인 전제로 복원.
|
# 흔한 오인식: vLLM → BLM (GPU 실전에서 재현). 기술 STT 도메인 전제로 복원.
|
||||||
|
# 주의: \b 경계는 유니코드 \w 기준이라 'BLM은'(공백 없음)은 교정하지 않는다.
|
||||||
|
# faster-whisper 출력은 어절 단위 공백 분리("BLM 서버를")라 실제로는 충분하다.
|
||||||
(re.compile(r"\bblm\b", re.IGNORECASE), "vLLM"),
|
(re.compile(r"\bblm\b", re.IGNORECASE), "vLLM"),
|
||||||
(re.compile(r"\bk ?u ?b ?e ?r ?n ?e ?t ?e ?s\b", re.IGNORECASE), "Kubernetes"),
|
(re.compile(r"\bk ?u ?b ?e ?r ?n ?e ?t ?e ?s\b", re.IGNORECASE), "Kubernetes"),
|
||||||
(re.compile(r"\bf ?a ?s ?t ?a ?p ?i\b", re.IGNORECASE), "FastAPI"),
|
(re.compile(r"\bf ?a ?s ?t ?a ?p ?i\b", re.IGNORECASE), "FastAPI"),
|
||||||
|
|||||||
Reference in New Issue
Block a user