fix: normalize faster-whisper segments to dicts + in-proc auto-worker
Colab run 3 (A100) surfaced three GPU/API-path bugs mocks couldn't catch: 1. faster-whisper yields namedtuple Segments, but batch/bench consume them as dicts (.get) -> AttributeError 'Segment' has no attribute 'get' on every real transcription. Engine now normalizes segments to dicts (_to_dict_segments) at the boundary. 2. API TranscribeOptions carries engine-irrelevant keys (formats, timestamps, glossary_id, post_correction, diarize); worker's TranscriptionOptions(**job.options) crashed with TypeError. Worker now filters job.options to TranscriptionOptions.__slots__. 3. in-proc server never consumed its own queue (jobs stayed queued forever). Added opt-in Settings.auto_worker (default off): lifespan starts a daemon Worker thread for inproc backend, stopped on shutdown. Notebook enables it via LUKESCRIBE_AUTO_WORKER=true so the API upload -> completed flow works end to end. Notebook: bench manifest now uses clips schema (audio_path/duration_sec/ entities); cell 22 reads error_message/error_code; upload poll window raised to 4min (first-run model download). + 5 tests (namedtuple/dict segments, API-style options, auto_worker on/off); 136 tests pass, ruff clean.
This commit is contained in:
@@ -220,6 +220,8 @@ def cells() -> list[dict]:
|
||||
"# 서버가 읽을 키 파일/큐를 명시 (cwd 의존 제거)\n"
|
||||
"os.environ['LUKESCRIBE_API_KEY_FILE'] = '/content/api_keys.json'\n"
|
||||
"os.environ['LUKESCRIBE_QUEUE_BACKEND'] = 'inproc'\n"
|
||||
"# in-proc 서버가 자체 워커 스레드로 큐를 소비 (업로드 → 완료까지 API 단독 처리)\n"
|
||||
"os.environ['LUKESCRIBE_AUTO_WORKER'] = 'true'\n"
|
||||
"\n"
|
||||
"!mkdir -p /content/logs\n"
|
||||
"!nohup luke-scribe serve --port 8000 > /content/logs/server.log 2>&1 &\n"
|
||||
@@ -265,10 +267,11 @@ def cells() -> list[dict]:
|
||||
"print('생성:', job)\n"
|
||||
"job_id = job.get('job_id')\n"
|
||||
"\n"
|
||||
"# 완료까지 poll (in-proc 큐는 워커가 소비해야 하므로 셀 12에서 drain 처리)\n"
|
||||
"# 완료까지 poll (auto-worker가 서버 프로세스에서 큐를 소비 — 첫 실행은\n"
|
||||
"# 모델 다운로드 ~1.6GB 포함이라 최대 4분까지 대기)\n"
|
||||
"if job_id:\n"
|
||||
" print('job_id =', job_id)\n"
|
||||
" for _ in range(60):\n"
|
||||
" for _ in range(120):\n"
|
||||
" st = json.loads(urllib.request.urlopen(\n"
|
||||
" urllib.request.Request(f'http://localhost:8000/v1/jobs/{job_id}',\n"
|
||||
" headers={'X-API-Key': RAW_KEY})\n"
|
||||
@@ -278,7 +281,7 @@ def cells() -> list[dict]:
|
||||
" break\n"
|
||||
" time.sleep(2)\n"
|
||||
" else:\n"
|
||||
" print('60초 내 미완료 — 셀 12(워커 drain) 실행 후 다시 확인')\n"
|
||||
" print('폴링 60초 초과 — 서버 로그 확인: /content/logs/server.log')\n"
|
||||
"else:\n"
|
||||
" print('업로드 실패 — 서버 로그 확인: /content/logs/server.log')\n"
|
||||
),
|
||||
@@ -315,7 +318,8 @@ def cells() -> list[dict]:
|
||||
" state = broker.get(job.id)\n"
|
||||
" print('결과 없음 — job 상태:', getattr(state, 'status', 'unknown'))\n"
|
||||
" if state is not None:\n"
|
||||
" print('job 오류:', getattr(state, 'error', None) or '없음')\n"
|
||||
" err = getattr(state, 'error_message', None) or getattr(state, 'error_code', None)\n"
|
||||
" print('job 오류:', err or '없음')\n"
|
||||
"else:\n"
|
||||
" print('status:', result.status)\n"
|
||||
" print('text:', result.text[:120])\n"
|
||||
@@ -332,11 +336,12 @@ def cells() -> list[dict]:
|
||||
"import yaml\n"
|
||||
"manifest = {\n"
|
||||
" 'name': 'colab-quick',\n"
|
||||
" 'dataset_version': '1.0',\n"
|
||||
" 'language': 'ko',\n"
|
||||
" 'targets': {'entity_preservation': 0.95, 'cer': 0.15},\n"
|
||||
" 'cases': [\n"
|
||||
" {'name': 'ko-en-tech', 'audio': 'samples/colab-ko-en.mp3',\n"
|
||||
" 'expected_entities': ['vLLM', 'Kubernetes', 'GPU']},\n"
|
||||
" 'clips': [\n"
|
||||
" {'name': 'ko-en-tech', 'audio_path': 'samples/colab-ko-en.mp3',\n"
|
||||
" 'duration_sec': 10.5, 'entities': ['vLLM', 'Kubernetes', 'GPU']},\n"
|
||||
" ],\n"
|
||||
"}\n"
|
||||
"yaml.safe_dump(manifest, open('/content/manifest.yaml', 'w'))\n"
|
||||
@@ -359,6 +364,10 @@ def cells() -> list[dict]:
|
||||
" (보안 설계). 셀 9에서 `RAW_KEY`를 캡처했는지 확인하세요 — 파일에서 키를 읽으면 401.\n"
|
||||
"2. **이전 실행에서 남은 서버**가 포트 8000을 점유하면 새 키를 모른 채 401이 납니다.\n"
|
||||
" 셀 10이 시작 시 `pkill`로 기존 서버를 종료하고 키 인증(HTTP 200)까지 검증합니다.\n\n"
|
||||
"### 업로드 후 job이 queued에 머무는 경우\n\n"
|
||||
"in-proc 백엔드는 별도 워커 프로세스가 없으면 큐를 소비하지 못합니다.\n"
|
||||
"셀 10이 `LUKESCRIBE_AUTO_WORKER=true`로 서버를 띄우면 서버 내부 워커 스레드가\n"
|
||||
"업로드 → 완료까지 처리합니다 (v0.1에서 추가된 옵트인 기능).\n\n"
|
||||
"### 모델 다운로드 실패\n\n"
|
||||
"- Hugging Face 연결 필요. 재시도: `LUKESCRIBE_MODEL_DOWNLOAD_RETRIES=3`\n"
|
||||
"- 특정 모델만: `--model large-v3-turbo` (기본) / `--model large-v3`\n"
|
||||
|
||||
Reference in New Issue
Block a user