도우바오 Seed로 B站 동반 시청 플러그인 제작, 요약·음성인식
도우바오 Seed로 B站 영상 요약과 구간 해설을 생성하고 음성인식으로 자막 없는 영상을 처리하는 동반 시청 플러그인을 만들었다.
중국어 원문을 AI로 번역했습니다. 고유명사와 수치는 원문 표기를 우선하며, 중요한 판단에는 아래 출처 원문을 함께 확인하세요.
20~30분짜리 영상을 다 보고 나서 이런 경험을 한 적 있나요? 그때는 설명이 꽤 좋다고 느꼈는데, 며칠 뒤 그중 한 가지 관점을 찾으려 해도 "아마 후반부에 있었던 것 같은데" 정도만 기억나는 그런 경우 말입니다.
이 문제를 해결하기 위해 저는 '더우바오 페이칸 도우미(豆包陪看助手)'라는 Chrome 확장 프로그램을 만들었습니다. B站 영상을 열고 페이지의 더우바오를 클릭하면, 영상을 함께 보면서 영상을 요약과 타임스탬프가 붙은 개요로 정리해 줍니다. 특정 구간을 다시 보고 싶을 때는 개요를 클릭해 그 위치로 돌아갈 수 있고, 해당 구간의 AI 해석을 펼쳐 볼 수도 있습니다.
그림 1: 실제 B站 페이지에서 0.2.0 확장 프로그램의 함께 보기 진입점.
처음에는 요구사항이 자막을 가져와 모델에 넘기면 끝나는 것처럼 보였습니다. 실제로 만들어 보니 영상 페이지, 자막, 음성, 모델, 브라우저 백그라운드가 각자 문제를 안고 있었습니다. 자막을 못 가져왔다면 정말 자막이 없는 건지, 아니면 네트워크 오류인 건지? 하나의 영상을 두 개의 탭에서 동시에 열면 요금이 두 번 청구되는 건 아닌지? 사용자가 이미 기록을 지웠는데, 늦게 도착한 모델 결과가 다시 기록을 써 버리는 건 아닌지?
이 글은 실제로 마주친 몇 가지 문제와 현재의 처리 방식을 기록한 것입니다. 프로젝트의 텍스트 모델 인터페이스는 사용자가 직접 설정합니다. 개발과 검수 과정에서 더우바오 Seed 모델을 사용했고, 0.2.0에는 선택 사항인 더우바오 음성 인식도 연동했습니다. 이는 B站의 공식 제품이 아닙니다. 0.2.0은 이미 Chrome 웹 스토어 심사를 제출했으며, 정식 출시 시점과 설치 진입점은 심사 결과에 따릅니다.
그림 2: 실제 B站 페이지의 요약과 구간별 해석으로, 0.0.1 버전의 실제 모델 검수 스크린샷에서 가져왔으며 UI는 현재 버전을 기준으로 합니다.
먼저 아키텍처: 더우바오 한 마리 뒤에는 여러 가지 일이 있다
확장 프로그램은 WXT, TypeScript, Chrome Manifest V3로 개발했습니다. 페이지 안의 더우바오, 패널, 플레이어 상태 감지는 Content Script가 담당합니다. B站 페이지 스타일이 확장 프로그램에 미치는 영향을 줄이기 위해 UI는 Shadow DOM 안에 두었습니다. 여기서의 격리는 주로 스타일과 컴포넌트 차원의 편의를 위한 것이며, 보안 샌드박스로 간주해서는 안 됩니다.
백그라운드 Service Worker는 대기열 처리, 중복 제거, 상태 조정을 담당합니다. 시간이 더 걸리거나 DOM 기능이 필요한 오디오 처리와 모델 호출은 Offscreen Document에 맡깁니다. 시청 기록, 전사, 요약, 작업 상태는 Dexie를 통해 IndexedDB에 저장하고, 설정과 Key는 브라우저 로컬 저장소를 사용합니다. B站, 텍스트 모델, 선택 사항인 음성 서비스는 모두 외부 의존성이며, 프로젝트 자체에는 별도의 비즈니스 서버가 없습니다.
그림 3: 제품 아키텍처 개략도로, 브라우저 내 각 부분의 역할과 외부 서비스 경계를 보여줍니다.
이런 구조는 비즈니스 서버의 배포 및 유지보수 비용을 없애고, 사용자도 별도의 제품 계정을 등록할 필요가 없습니다. 대신 사용자가 직접 모델 서비스를 설정해야 하고, 로컬 기록도 자동으로 기기 간 동기화되지 않습니다. 규모가 크지 않은 확장 프로그램으로서는 이 절충을 받아들였습니다.
또 하나 겉으로는 사소해 보이지만 실제로는 비용에 영향을 주는 세부 사항은 트리거 시점입니다. 새로 설치하면 기본적으로 프런트에서 유효 재생이 10초에 도달해야 정리를 시작하며, 일시 정지하거나 백그라운드로 전환하면 누적되지 않습니다. 구현 시 플레이어의 미디어 시간 증가량을 기준으로 시간을 재며, 진행 바를 드래그해 생기는 큰 점프는 유효 시청으로 치지 않습니다. 그렇지 않으면 사용자가 페이지를 열어 잠깐 보거나 진행 바를 한 번 드래그하기만 해도 모델 호출 한 라운드가 트리거될 수 있습니다.
첫 번째 함정: 영상은 21분인데 개요는 7분까지만 써졌다
초기 검수 때, 영상 길이가 21분 12초인 샘플이 있었는데 확장 프로그램이 요약은 분명히 생성했고 개요도 그럴듯해 보였습니다. 하지만 마지막 항목을 자세히 보니 개요는 07:47에서 멈춰 있었습니다. 원본 기록에는 실제로 전체 587개의 자막이 저장되어 있었고, 마지막 자막은 1270.92초에서 끝났으니 문제는 "자막을 앞부분만 가져온 것"이 아니었습니다.
확인해 보니 두 가지 원인이 있었습니다. 첫째, 원래는 개요의 구조와 항목 수만 검증하고 앞·중·후반 구간이 커버됐는지는 확인하지 않았습니다. 둘째, 어떤 구간 해석의 입력이 6000자를 넘으면 기존 구현이 뒷부분을 그대로 잘라냈습니다.
이런 문제는 "모델이 성공을 반환했다"는 사실에 쉽게 가려집니다. JSON 형식이 맞고 노드 수가 맞다고 해서 사용자가 전체 영상을 회고하는 데 쓸 만한 노트를 받았다는 뜻은 아닙니다.
그래서 이후 몇 가지 작업을 했습니다. 긴 자막은 타임스탬프가 붙은 내용을 기준으로 분할하며, 기본적으로 각 블록은 약 14400자이고, 블록 사이에는 예산이 허락할 때 최대 약 30초의 겹침을 두어 경계에서 맥락이 끊기는 일을 줄였습니다. 각 블록은 먼저 국부 요점을 추출하고, 그 요점을 모델에 넘겨 종합합니다. 기본적으로 최대 3개 블록을 동시에 처리합니다. 지나치게 긴 단일 구간 해석도 같은 방식으로 전체 여러 블록을 처리한 뒤 병합하도록 바꾸고, 더 이상 뒷부분을 단순히 버리지 않습니다.
모델 출력이 돌아온 뒤에는 구조를 검사하는 것 외에도 시간이 순서대로인지, 기존 자막 범위 안에 있는지, 그리고 긴 영상의 앞·중·후반이 충분히 커버됐는지도 확인합니다. 커버리지가 부족하면 오류 안내와 함께 재시도하고, 다시 충족되지 않으면 실패로 보고합니다. 여기서의 커버리지 검사는 엔지니어링 안전장치로, 명백한 누락은 발견할 수 있지만 모든 요점이 정확하다는 것을 증명하지는 않으며, 자막이 없는 시간에 대해 모델이 내용을 꾸며내도록 요구하지도 않습니다.
그림 4: 0.0.2 단계의 실제 Chrome 검수 스크린샷으로, 화면은 확장 프로그램 패널을 잘라낸 것이며, 이 샘플은 수정 후 마지막 개요가 20:35에 위치합니다.
수정 후, 여전히 이 21:12 샘플에서 마지막 개요는 20:35에 도달했고 마지막 구간도 해석을 펼쳐 볼 수 있었습니다. 또 다른 27:44와 41:06의 실제 영상 샘플에서도 개요의 마지막 항목이 각각 26:00과 40:30에 도달했습니다. 이는 실제 Chrome과 실제 모델 서비스로 진행한 샘플 검사이며, 어떤 영상에서도 누락이 없다는 것을 뜻하지도 않고, 요약의 사실 정확도가 특정 비율에 도달했다는 것도 아닙니다.
이 함정이 준 교훈은 이것입니다. **긴 콘텐츠 요약을 만들 때는 검수에서 앞쪽 몇 개 항목과 인터페이스의 오류 보고 여부만 봐서는 안 됩니다.** 최소한 원본 영상의 앞·중·후반 구간과 대조해야 하며, 특히 마지막 구간이 실제로 처리됐는지 반드시 확인해야 합니다.
두 번째 함정: 자막을 못 가져온 것이 영상에 자막이 없다는 뜻은 아니다
바로 쓸 수 있는 자막이 있으면 저는 자막을 우선 사용합니다. 먼저 사용 가능한 수동 중국어 자막을 고르고, 그다음 중국어 자막 중 AI 자막을 고려합니다. 자막 자체에 시간 정보가 있고, 보통은 전체 오디오를 따로 내려받아 음성 인식 서비스를 호출할 필요도 없습니다.
하지만 "자막 획득 실패"와 "사용 가능한 중국어 자막이 없음을 확인"은 다른 문제입니다. 로그인 상태 만료, 네트워크 오류, 사이트 리스크 컨트롤, 또는 인터페이스 응답 구조 이상 등으로 자막을 못 가져올 수 있습니다. 이런 상황을 모두 하나의 if (!subtitle) 로 묶어 곧바로 음원 다운로드로 넘어가면, 사용자가 모르는 사이에 오디오를 업로드하고 음성 사용량을 소모할 수 있습니다.
그림 5: 자막 우선 처리 흐름 개략도. 예외와 실제로 자막이 없는 경우가 서로 다른 분기로 나뉩니다.
현재 처리는 이렇습니다. 먼저 "사용 가능한 자막 있음", "사용 가능한 중국어 자막이 없음을 확인", "획득 과정에서 오류 발생"을 구분합니다. 자막이 없다고 확인되었고, 사용자가 이미 음성 서비스를 설정하고 권한을 부여한 경우에만 전체 음원을 자동으로 내려받아 선택한 서비스에 넘겨 인식시킵니다. 네트워크, 로그인, 리스크 컨트롤 오류는 처리 안내를 표시하며, 그 때문에 오디오를 자동으로 전송하지는 않습니다.
이 분기를 검증하기 위해, 나는 로그인 상태의 실제 B站 샘플 두 개도 확인했다. 하나는 사람이 만든 자막이 있고, 다른 하나는 AI 자막이 있다. 요약 모델은 로컬 모의 서비스를 사용했다. 모니터링이覆盖한 확장 백그라운드와 오프스크린 페이지에서 두 번 모두 오디오 다운로드나 음성 인식 요청은 없었다. 이 결과는 해당 회차의 두 샘플 행동만을 설명하며, 모든 네트워크 조건이 검증되었다는 뜻은 아니다.
그림 6: 0.2.0 확장이 실제 B站 페이지에서 보여주는 음성 서비스 설정 화면으로, 실제 키는 입력하지 않았다.
이 결정은 제품상의 책임도 수반한다. 오디오 트랙은 사용자가 선택한 제3자 서비스로 전송되며, 비용이 발생할 수 있고, 사용자가 아직 보지 않은 내용을 미리 처리할 수도 있다. 그래서 설정 화면에서는 전송 범위, 비용, 스포일러 위험을 분명히 밝혀야 한다. 요약을 생성할 때 자막이나 전사, 그리고 필요한 영상 정보 역시 사용자가 설정한 텍스트 모델로 전송된다. 「기록이 로컬에 저장된다」는 것이 「모든 데이터가 브라우저를 벗어나지 않는다」는 뜻은 아니다. Key를 브라우저 로컬에 저장하는 것도 암호화되었다는 뜻이 아니므로, 설정할 때는 여전히 신뢰하는 서비스를 선택해야 한다.
세 번째 함정: 음성 인식이 빨라지자 메모리도 올라갔다
최초의 방안은 거의 실시간 재생 방식으로 오디오를 추출한 뒤, 실시간 속도로 전송하는 것이었다. 이 발상은 비교적 직관적이지만, 13분짜리 영상을 처리할 때 전송만 해도 거의 13분이 걸릴 수 있었고, 다운로드, 인식, 요약은 아직 계산에 넣지도 않은 상태였다.
이후 Doubao 음성 경로는 다음과 같이 바뀌었다. 전체 오디오 트랙을 다운로드하고, 확장의 오프스크린 페이지에서 16 kHz 모노 PCM으로 디코딩한 뒤, 통제된 버퍼로 음성 서비스에 전송한다. 전체 전사가 시간과 내용 등의 검사를 통과한 뒤에야 부분 요점과 전체 영상 요약 정리를 이어 간다. 유효한 전사는 이후 요약 처리에서 재사용할 수도 있다.
타임스탬프에서도 함정을 밟았다. 전사를 재사용한 진단 과정에서, 두 차례 생성된 개요 모두 영상 길이를 초과하는 시점이 나타났고, 분·초와 총 초를 혼동한 것이 원인 후보로排查되었다. 이후 ASR 요약 입력은 명확한 정수 총 초를 사용하도록 바꾸었다. 예를 들어 10:12를 612초로 표시하고, 출력 단에서 범위와 순서를 검사한다. 이렇게 하면 일부 명백한 오류는 막을 수 있지만, 여전히 원본 영상과 대조해 시점과 내용이 맞는지 확인해야 한다.
한 번의 통제된 대조 실험에는 같은 28.448초짜리 합성 중국어 음성을 사용했다. 실시간 속도로 전송했을 때 첫 패킷부터 최종 반환까지 약 29.384초가 걸렸고, 빠른 경계 전송은 약 3.717초였다. 이 숫자는 해당 전송과 반환 과정만 비교한 것으로, 오디오 다운로드, 디코딩, 요약은 포함하지 않으며 제품의 엔드투엔드 소요 시간으로 삼을 수 없다.
속도를 얻은 대가는 자원 압박이었다. 또 다른 격리된 Chrome 테스트에서 약 13분짜리 모노 합성 오디오를 오프라인으로 디코딩한 뒤, 브라우저 프로세스 트리의 RSS가 기준선 대비 약 447 MiB 증가하는 것을 관찰했다. 여기에는 공유 메모리가 포함되었을 수 있으며, 다른 기기나 스테레오 영상에 그대로 적용할 수는 없다. 적어도 「오디오 파일이 커 보이지 않는다」는 이유로 디코딩 후의 메모리 오버헤드를 무시해서는 안 된다는 점은 보여 준다.
그래서 현재 Doubao Agent Plan 경로에는 프로젝트 측 경계를 두었다. 최대 15분, 오디오 트랙 25 MiB 이하, 최대 스테레오까지다. 이것은 서비스 제공자의 공식 상한이 아니다. 초과하거나完整性을 확인할 수 없을 때는, 일부만 처리한 결과를 「전체 영상 요약」으로 적기보다 실패를 안내하는 쪽을 택한다. 앞으로 더 긴 영상을 지원하려면 분할 디코딩, 자원 점유, 경계 정렬을 계속 연구해야 하며, 단순히 재생 시간 제한을 늘리는 것만으로는 안 된다.
네 번째 함정: 백그라운드가休眠할 수 있고, 늦게 도착한 결과도 돌아온다
Chrome 확장의 Service Worker는 항상 온라인인 백그라운드 프로세스가 아니다. Chrome 공식 수명 주기 설명에 따르면, 유휴 등의 조건에서 종료될 수 있으며 전역 변수도 함께 사라진다. Offscreen Document는 숨겨진 페이지와 DOM 기능을 제공할 수 있지만, 작업 복구 설계를 대체할 수는 없다. 구체적인 제한은 Chrome Offscreen API 문서를 참고하라.
프로젝트는 작업과 상태를 IndexedDB에 기록하고, 대기 중, 실행 중, 완료, 실패 등의 상태를 구분한다. 같은 세션, 영상, 작업 유형, 분할의 활동 중 작업은 대기열 트랜잭션에서 중복을 검사해, 두 탭이 동시에 중복 작업을 발생시키는 것을 막는다. 백그라운드가 복구되면 작업 유형에 따라 이후 처리를 판단한다.
음성 작업에는 추가 문제가 있다. 요청이 중단되었다고 해서 서버 측에서 반드시 처리하지 않았다거나 과금되지 않았다고 할 수는 없다. 따라서 과금 상태가 불명확할 때 확장은 음성을 조용히 재전송하지 않고, 사용자에게 재시도 여부를 결정하도록 안내한다. 일반 작업과 음성 작업은 단순히 「실패하면 한 번 더 시도」하는 전략을 함께 쓸 수 없다.
더 은밀한 경쟁 조건도 있다. 사용자가 기록을 비울 때 원격 요청은 이미 나가 있을 수 있다. 취소를 호출했다 해도 이미 진행 중인 모든 조작이 즉시 멈춘다고 가정할 수는 없다. 현재 작업에는 실행 식별자 runId가 붙는다. ASR 체인은 취소 신호를 중단 가능한 조작으로 전달하고, 결과를 기록할 때 데이터베이스 트랜잭션에서 작업과 세션 상태를 다시 확인한다. 작업이 이미 무효라면 기록을 거부해, 오래된 결과가 비운 뒤에 다시 나타나는 것을 막는다.
이 메커니즘의 목적은 외부 서비스가 항상 안정적임을 보장하는 것이 아니라, 중단, 재시도, 취소에 명확한 결과가 있게 하는 것이다. 사용자 할당량을 소모하는 AI 기능에서는 이 점이 모델 자체의 효과만큼이나 신중히 설계할 가치가 있다.
지금 어디까지 검증했고, 무엇이 남았나
0.2.0까지의 로컬 검수 기록으로는 672개의 단위 및 통합 테스트가 통과했고, 별도로 16개의 격리 브라우저 회귀 테스트가 통과했으며, 자막 우선, 두 탭 중복 제거, 취소, 재시도 등의 시나리오를 커버한다. 후자는 모의 B站, 음성, 요약 서비스를 사용하므로, 실제 서비스가 각종 네트워크 환경에서 안정적임을 증명하는 데 쓸 수는 없다.
실제 서비스 측면에서는, 이전의 0.2.0 개발 후보가 실제 로그인 환경에서 약 12분 56초짜리 영상의 오디오 다운로드, 음성 인식, 요약을 완료했다. 당시 ASR 작업 생성부터 완료까지 약 286.83초가 걸렸으며, 인식과 이후 요약을 포함한다. 이는 단일 결과이며 성능 약속이 아니다. 최종 0.2.0 빌드는 반복 검수를 위해 실제 오디오를 다시 전송하지 않았고, 장시간 영상의 자원 점유, 체계적인 시간 오차, 다중 P 영상, 그리고 Windows와 기타 브라우저에서의 동작은 여전히 계속 검증해야 한다.
돌아보면 이 프로젝트에서 가장 수확이 큰 부분은, 「그럴듯한 글 한 토막을 생성하는 것」을 점차 「사용자가 이 글이 어디서 왔는지, 어디까지 커버하는지, 오류가 나면 어떻게 되는지 알게 하는 것」으로 바꿔 간 일이었다. 앞으로는 먼저 스토어 심사와 실제 환경 추가 검증을 진행하고, 피드백에 따라 내보내기, 영상 Q&A 등의 기능을 고려할 것이다. 이들은 아직 출시 시점이 정해지지 않았다.
만약 당신도 비슷한 AI 도구를 만들고 있다면, 실제 작업의 실패 방식에서 거꾸로 설계하기를 적극 권한다. 입력이 빠질 수 있는지, 모델이漏할 수 있는지, 작업이 중단될 수 있는지, 재시도가 사용자에게 더 많은 비용을 지우게 할 수 있는지. 이 질문들에 하나하나 명확히 답하면, 경험은 보통 예쁜 프롬프트를 하나 더 추가하는 것보다 더 탄탄해진다.
神鹰手哥_起飞版
12
글
455
조회
0
팬