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 |
| 领域 | 新闻、研究 |
| 复杂度 | 中级 |