采访转录Skill interview-transcription

采访转录技能用于记者管理采访全过程,包括采访准备、录音设置、音频转录、源笔记整理、时间戳引用生成和采访数据库构建。关键词:采访管理、音频转录、记者工作流、源关系维护、转录工具。

字幕翻译 0 次安装 0 次浏览 更新于 3/15/2026

name: 采访转录 description: 采访管理、转录工作流程和记者源笔记记录。用于准备采访、管理录音、转录音频/视频、组织源笔记、创建时间戳引用或建立采访数据库。对进行采访和管理源关系的记者至关重要。

采访转录和管理

从准备到发表的实用工作流程,帮助记者管理采访。

何时激活

  • 准备采访问题
  • 处理音频/视频录音
  • 创建或管理转录稿
  • 组织多个源的笔记
  • 建立源关系数据库
  • 生成时间戳引用用于事实核查
  • 将录音转换为可发布的引用

采访前准备

研究清单

在录音开始前,您应该已经知道:

## 源准备:[姓名]

### 背景
- 角色/职位:
- 组织:
- 他们为什么对这个故事相关:
- 以前的媒体露面(注意不一致之处):

### 关键问题(优先级)
1. [必须问的问题]
2. [必须问的问题]
3. [如果时间允许]

### 参考文件
- [ ] 携带/分享 [具体文件]
- [ ] 询问关于 [具体声明/数据点]

### 红线
- 他们可能避免的话题:
- 需要谨慎处理的敏感领域:

录音设置

# 标准录音配置
RECORDING_SETTINGS = {
    'format': 'wav',           # 无损转录
    'sample_rate': 44100,      # 标准质量
    'channels': 1,             # 单声道适合语音
    'backup': True,            # 始终运行备份录音器
}

# 文件命名约定
# 年-月-日_源姓氏_主题.wav
# 示例:2024-03-15_smith_预算听证.wav

两设备规则:始终在两个设备上录音。手机至少作为备份。

转录工作流程

自动转录管道

from pathlib import Path
import subprocess
import json

def transcribe_interview(audio_path: str, output_dir: str = "./transcripts") -> dict:
    """
    使用带说话者识别的Whisper进行转录。
    返回带时间戳的转录稿。
    """
    Path(output_dir).mkdir(exist_ok=True)

    # 使用whisper.cpp或OpenAI Whisper
    result = subprocess.run([
        'whisper',
        audio_path,
        '--model', 'medium',
        '--output_format', 'json',
        '--output_dir', output_dir,
        '--language', 'en',
        '--word_timestamps', 'True'
    ], capture_output=True)

    # 加载并返回结构化转录稿
    json_path = Path(output_dir) / f"{Path(audio_path).stem}.json"
    with open(json_path) as f:
        return json.load(f)

def format_for_editing(transcript: dict) -> str:
    """转换为记者友好的带时间戳格式。"""
    lines = []
    for segment in transcript.get('segments', []):
        timestamp = format_timestamp(segment['start'])
        text = segment['text'].strip()
        lines.append(f"[{timestamp}] {text}")
    return '

'.join(lines)

def format_timestamp(seconds: float) -> str:
    """将秒转换为HH:MM:SS格式。"""
    h = int(seconds // 3600)
    m = int((seconds % 3600) // 60)
    s = int(seconds % 60)
    return f"{h:02d}:{m:02d}:{s:02d}"

手动转录模板

对于敏感采访或当AI转录失败时:

## 转录稿:[源] - [日期]

**录音文件**:[文件名]
**时长**:[XX:XX]
**转录者**:[姓名]
**对照录音验证**:[ ] 是 / [ ] 否

---

[00:00:15] **Q**:[您的问题]

[00:00:45] **A**:[源回答 - 逐字记录,包括嗯、停顿标记为(...)]

[00:01:30] **Q**:[跟进问题]

[00:01:42] **A**:[回答]

---

## 笔记
- [任何未在音频中捕捉的内容:手势、展示的文件等]

## 潜在引用
- [00:01:42] "突出引用" - 背景:[为什么重要]

引用提取和验证

提取引用工作流程

from dataclasses import dataclass
from typing import Optional
import re

@dataclass
class Quote:
    text: str
    timestamp: str
    speaker: str
    context: str
    verified: bool = False
    used_in: Optional[str] = None

class QuoteBank:
    """管理采访转录稿中的引用。"""

    def __init__(self):
        self.quotes = []

    def extract_quote(self, transcript: str, start_time: str,
                      end_time: str, speaker: str, context: str) -> Quote:
        """提取并存储带元数据的引用。"""
        # 提取时间戳之间的文本
        pattern = rf'\[{re.escape(start_time)}\](.+?)(?=\[\d|$)'
        match = re.search(pattern, transcript, re.DOTALL)

        if match:
            text = match.group(1).strip()
            quote = Quote(
                text=text,
                timestamp=start_time,
                speaker=speaker,
                context=context
            )
            self.quotes.append(quote)
            return quote
        return None

    def verify_quote(self, quote: Quote, audio_path: str) -> bool:
        """对照原始录音标记引用为已验证。"""
        # 实际中:在时间戳处听音频,确认准确性
        quote.verified = True
        return True

    def export_for_story(self) -> str:
        """导出已验证引用,准备发布。"""
        output = []
        for q in self.quotes:
            if q.verified:
                output.append(f'"{q.text}"
— {q.speaker}
[时间戳: {q.timestamp}]')
        return '

'.join(output)

引用准确性清单

发布任何引用前:

- [ ] 在时间戳处听原始录音
- [ ] 引用是逐字的(或明确标记为意译)
- [ ] 上下文保留(未断章取义改变意思)
- [ ] 说话者正确识别
- [ ] 时间戳记录供事实核查员使用
- [ ] 源批准引用(如果达成协议)

源管理数据库

采访跟踪模式

from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional
from enum import Enum

class SourceStatus(Enum):
    ACTIVE = "active"           # 当前参与
    DORMANT = "dormant"         # 近期未联系
    DECLINED = "declined"       # 拒绝参与
    OFF_RECORD = "off_record"   # 仅限背景

class InterviewType(Enum):
    ON_RECORD = "on_record"
    BACKGROUND = "background"
    DEEP_BACKGROUND = "deep_background"
    OFF_RECORD = "off_record"

@dataclass
class Source:
    name: str
    organization: str
    contact_info: dict  # 电子邮件、电话、Signal等
    beat: str
    status: SourceStatus = SourceStatus.ACTIVE
    interviews: List['Interview'] = field(default_factory=list)
    notes: str = ""

    # 关系跟踪
    first_contact: Optional[datetime] = None
    trust_level: int = 1  # 1-5等级

@dataclass
class Interview:
    source: str
    date: datetime
    interview_type: InterviewType
    recording_path: Optional[str] = None
    transcript_path: Optional[str] = None
    story_slug: Optional[str] = None
    key_quotes: List[str] = field(default_factory=list)
    follow_up_needed: bool = False
    notes: str = ""

快速源查找

def find_sources_for_story(sources: List[Source], topic: str,
                           beat: str = None) -> List[Source]:
    """为新故事查找相关源。"""
    matches = []
    for source in sources:
        # 如果指定了领域,则过滤
        if beat and source.beat != beat:
            continue
        # 仅建议活跃源
        if source.status != SourceStatus.ACTIVE:
            continue
        # 检查他们是否在类似话题上发表过言论
        for interview in source.interviews:
            if topic.lower() in interview.notes.lower():
                matches.append(source)
                break

    # 按信任等级排序
    return sorted(matches, key=lambda s: s.trust_level, reverse=True)

音频/视频处理

批量处理多个录音

from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
import json

def batch_transcribe(recordings_dir: str, output_dir: str) -> dict:
    """处理目录中的所有录音。"""
    recordings = list(Path(recordings_dir).glob('*.wav')) + \
                 list(Path(recordings_dir).glob('*.mp3')) + \
                 list(Path(recordings_dir).glob('*.m4a'))

    results = {}

    with ProcessPoolExecutor(max_workers=4) as executor:
        futures = {
            executor.submit(transcribe_interview, str(rec), output_dir): rec
            for rec in recordings
        }

        for future in futures:
            rec = futures[future]
            try:
                transcript = future.result()
                results[rec.name] = {
                    'status': 'success',
                    'transcript': transcript
                }
            except Exception as e:
                results[rec.name] = {
                    'status': 'error',
                    'error': str(e)
                }

    return results

视频采访提取

import subprocess

def extract_audio_from_video(video_path: str, output_path: str = None) -> str:
    """从视频中提取音频轨道用于转录。"""
    if output_path is None:
        output_path = video_path.rsplit('.', 1)[0] + '.wav'

    subprocess.run([
        'ffmpeg', '-i', video_path,
        '-vn',  # 无视频
        '-acodec', 'pcm_s16le',  # WAV格式
        '-ar', '44100',  # 采样率
        '-ac', '1',  # 单声道
        output_path
    ], check=True)

    return output_path

法律和伦理考虑

同意文档

## 录音同意记录

**日期**:
**源名称**:
**录音类型**:[ ] 音频 [ ] 视频
**采访类型**:[ ] 在记录 [ ] 背景 [ ] 记录外

### 获得的同意:
- [ ] 口头同意在采访开始时录制
- [ ] 签署书面同意表
- [ ] 电子邮件确认同意

### 管辖地笔记:
- 采访地点州/国家:
- 单方或双方同意管辖地:
- 任何同意的特定限制:

### 同意的条款:
- [ ] 允许完全归属
- [ ] 仅组织归属
- [ ] 匿名源
- [ ] 发布前审查引用
- [ ] 禁运至 [日期]:

双方同意州(美国)

加利福尼亚、康涅狄格、佛罗里达、伊利诺伊、马里兰、马萨诸塞、密歇根、蒙大拿、内华达、新罕布什尔、宾夕法尼亚、华盛顿需要所有方同意。

无论管辖地如何,始终获得录音的明确同意

工具和资源

工具 目的 笔记
Whisper 本地转录 免费、准确、私密
Otter.ai 云转录 实时、说话者识别
Descript 像文本一样编辑音频 适合提取片段
Rev 人工转录 用于敏感/法律
Trint 记者专用 协作功能
oTranscribe 免费网页播放器 手动转录辅助

相关技能

  • 源验证 - 在采访前验证源凭证
  • 信息自由法请求 - 获取文件以告知采访问题
  • 数据新闻 - 分析采访中提到的数据源

技能元数据

字段
版本 1.0.0
创建日期 2025-12-26
作者 Claude Skills for Journalism
领域 新闻、研究
复杂度 中级