Skip to content

ASR and Video Analysis ko

Hermes Agent edited this page Oct 1, 2026 · 1 revision

ASR 및 영상 분석

English | 中文 | 日本語 | 한국어 | Español | Português | Русский

자막 없는 Bilibili / YouTube 비디오를 첨부하면 browsa는 페이지 안에서 오디오를 가져오고, 클라우드 ASR을 돌려 [mm:ss] 트랜스크립트를 만든다 — 또는 视听精读(영상·오디오 정독)을 돌린다: 발화 + 화면을 담은 그림-텍스트 문서. 오늘의 ASR 프로바이더는 Volcengine Ark다.

왜 "다운로드 → 파일 업로드"이지 URL 직접 전달이 아닌가

URL 직접 전달은 두 플랫폼 모두에게 죽었다: Bilibili는 CDN URL을 사용자 세션 IP에 서명한다(Ark 서버는 가져올 수 없다); YouTube는 PO 토큰 + 세션 + 쿠키 결합을 얹는다(서버 측 페치는 403). 브라우저 — 서명과 IP가 일치하는 바로 그 클라이언트 — 가 바이트를 직접 페치해 Files API에 업로드해야 한다. 이것은 근본 원인에 대한 결론이지, 여러 선택지 가운데 하나가 아니다.

파이프라인 (여덟 단계)

  1. ATTACH_PAGE가 {mode:'asr-pending'}을 반환한다(지연 저장 핸드오프).
  2. buildAsrPendingCtx가 플랫폼별로 디스패치한다: Bilibili는 콘텐츠 스크립트를 재주입해 스트림을 읽는다; YouTube는 MAIN 월드 __browsaFetchFreshYouTubeStreams를 호출한다(현재 PO 토큰을 주조하는 새 /player 요청).
  3. 스트림 선택: 최저 비트레이트 순 오디오(어차피 트랜스코딩된다)이지만 진짜 길이의 90% 미만인 스트림은 기각한다(실제 잘린 스트림 사건); AAC-LC 선호(decodeAudioData는 HE-AAC를 거절할 수 있다).
  4. DNR 헤더 주입(lib/sidepanel/media-headers.js): Bilibili는 Referer가 필요; YouTube는 Origin 재작성 + 쿠키도 필요(googlevideo는 헤더 없는 확장 페치에 403 — 라이브 검증).
  5. 16kHz 모노 WAV로 트랜스코딩: Bilibili m4s는 비디오 없는 fMP4 MP4다; Ark는 파일을 내용 기준으로 "video"로 분류한다 → Invalid video_url → status failed. WAV가 경험적으로 증명된 포맷이다. Web Audio 디코드 + 손작성 선형 보간 리샘플(순수, Node 테스트 가능).
  6. Files API 업로드(≤512MB 멀티파트): expire_at = 30일, 의미 있는 파일명; browsaArkFileCache가 file_id를 저장한다(키 = base|key-fingerprint|assetId) — 같은 비디오는 30일 안에 재업로드를 건너뛴다(재사용 전 생존 프루브).
  7. 파일 상태 폴링 → /responses로 스트리밍 전사(input_audio.file_id), 프롬프트가 줄마다 [mm:ss]를 강제한다.
  8. ATTACH_ASR_CONFIRM이 트랜스크립트 + videoSrc 스탬프를 저장한다(타임스탬프 필 / 타임라인 드로어의 전제조건).

절단 방어 — 부분 트랜스크립트를 조용히 저장하지 않는다 (네 층, 사건 기반)

  1. /responses에 명시적 max_output_tokens: 65536 (모델 기본 출력 상한이 오디오 한가운데서 조용히 자른다).
  2. SSE incomplete / finish_reason:'length' 신호를 파스 → truncated:true.
  3. 완결성 게이트: 마지막 타임스탬프 < 비디오 길이의 90% → throw, 평문 + 토스트로 fail open(저장하지 않는다).
  4. 구멍 게이트: largestTranscriptGapSec이 타임라인을 구간 병합한다; 300초를 넘는 구멍은 기각한다(81분 비디오가 한때 중간의 한 시간을 잃었다).

비디오 정독 (비디오 자체가 모델에게 간다)

input_video (+ 선택적 별도 input_audio), max_output_tokens 65536, 스트리밍 그림-텍스트 출력. 프롬프트 규율(실제 실행으로 보정됨): 어떤 두 번째 목소리든 나타나면 화자를 라벨하고, 식별 가능한 이름을 붙이며, 광고 낭독은 한 줄로 압축하고, 키프레임 스크린샷은 논지가 그것을 보는 데 의존할 때만 (소프트 밀도 힌트 + 명시적 촬영 금지 목록; 유일한 하드 상한은 클라이언트 측 SAFETY_KEYFRAME_CAP 24 — 병적 출력 가드지 품질 노브가 아니다). [图N] 마커는 페이지 이미지 및 타임라인 드로어와 하나의 앵커링 프로토콜을 공유한다.

플랫폼 노트

  • Bilibili: /x/player/wbi/v2 트랙 목록 + CDN 자막 JSON을 능동적으로 페치 — CC 토글과 무관.
  • YouTube: timedtext는 오직 플레이어 자신의 POT 실린 요청에만 진짜 내용을 준다(captionTracks.baseUrl 직접 페치는 빈 본문); 인터셉터는 CC가 한 번이라도 켜졌을 때만 재료를 잡는다. 폴백 단계 2c는 승인된 요청 하나를 주조하러 플레이어의 자막 모듈을 구동한다(화면의 짧은 자막 번쩍임은 예상된 것); 트랙목록-빈 판정은 videoId별로 네거티브 캐시된다.
  • "자막 없음" 판정은 ## 字幕 텍스트 마커가 아니라 구조화된 noTranscript 플래그에서 나온다(오토 모드의 조용한 Jina 폴백이 텍스트 마커를 삼킨다 — 실제 버그).

제2 ASR 프로바이더를 위한 이음새 (예약됨)

lib/asr-providers.js(메타데이터 레지스트리; UI 변경 0) + attach-asr.js의 ASR_ADAPTERS(동일 시그니처 {transcribeAudio, analyzeVideo}). 어려운 부분은 언제나 엔드포인트의 파일 업로드 능력이다(긴 오디오는 인라인 base64에 실을 수 없다). 완전한 Qwen/DashScope 어댑터가 만들어졌다가 하루 만에 제거되었다(브라우저→OSS 불안정; git 히스토리에 보존); tabCapture 재생하며 녹음 폴백은 기각되었다(일시정지/스킵 구간은 침묵 — 재생되지 않은 비디오는 전사될 수 없다).


원본 출처: AGENTS.md "Video ASR subtitles", "YouTube transcript acquisition vs POT"; attach-asr.js 헤더 주석(전체 역사). 권위판: ASR-and-Video-Analysis(영어) / ASR-and-Video-Analysis-zh(중국어) — AI 초벌 번역 스냅숏, 동기화 2026-10-01.

Clone this wiki locally