AI辅助演讲:从文稿到交付

引言

演示文稿只是演讲的载体,真正的价值在于演讲本身。AI 正在改变演讲的全生命周期:从文稿撰写、排练反馈到现场辅助和事后分析。本文系统梳理 AI 辅助演讲的技术和工具,帮助演讲者从准备到交付全面提升。

一、演讲全生命周期

准备阶段                  排练阶段              交付阶段            复盘阶段
─────────               ─────────            ─────────          ─────────
主题研究                  语速分析              实时提词器          观众反馈分析
大纲生成                  停顿检测              时间管理            问答质量评估
文稿撰写                  填充词统计            现场字幕            改进建议
PPT 制作                  语调分析              同声翻译            知识沉淀
Speaker Notes            肢体语言              直播互动            精彩片段
                         模拟 Q&A

二、AI 文稿撰写

2.1 演讲稿结构框架

经典演讲结构(15-20 分钟):

开场(2分钟)
├─ 钩子(引人入胜的故事/数据/问题)
├─ 自我介绍(一句话)
└─ 预览(今天我们要讨论三个话题...)

主体(10-13分钟)
├─ 论点1(3-4分钟)
│   ├─ 陈述
│   ├─ 证据(数据/案例/故事)
│   └─ 过渡(连接到下一个论点)
├─ 论点2(3-4分钟)
│   └─ 同上结构
└─ 论点3(3-4分钟)
    └─ 同上结构

结尾(3-5分钟)
├─ 回顾(重申三个要点)
├─ 行动号召(希望观众做什么)
└─ 收尾(回扣开场钩子 / 金句)

2.2 LLM 生成演讲稿

SPEECH_WRITING_PROMPT = """
你是一位资深的演讲教练。请为以下演讲生成完整的演讲稿。

主题:{topic}
时长:{duration} 分钟
受众:{audience}
场合:{occasion}
风格:{style}

要求:
1. 使用口语化表达,适合大声朗读
2. 每段标注预计时长
3. 标注[停顿]、[强调]、[环视观众]等舞台指示
4. 包含 1-2 个故事/案例
5. 开场必须有一个强钩子
6. 结尾必须有行动号召
7. 每个关键论点后加过渡句
8. 总字数约 {word_count} 字(中文约 200 字/分钟)

输出格式:
## [章节名] (预计 X 分钟)

[演讲稿内容]

[舞台指示]
"""

def generate_speech(topic: str, duration: int = 15,
                    audience: str = "行业从业者",
                    style: str = "专业但不失亲和") -> str:
    """生成演讲稿"""
    word_count = duration * 200  # 中文约 200 字/分钟

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": SPEECH_WRITING_PROMPT.format(
                topic=topic, duration=duration, audience=audience,
                occasion="行业大会", style=style, word_count=word_count
            )},
            {"role": "user", "content": f"请为我写一篇关于"{topic}"的演讲稿。"}
        ],
        temperature=0.8,
        max_tokens=4000
    )
    return response.choices[0].message.content

2.3 Speaker Notes 生成

def generate_speaker_notes(slides: list[dict],
                           total_minutes: int = 20) -> list[dict]:
    """为每页幻灯片生成 Speaker Notes"""
    minutes_per_slide = total_minutes / len(slides)

    prompt = f"""
    为以下幻灯片生成演讲备注(Speaker Notes)。

    规则:
    1. 每页备注约 {int(minutes_per_slide * 200)} 字({minutes_per_slide:.1f} 分钟)
    2. 口语化,可以直接朗读
    3. 包含过渡语(从上一页到这一页的衔接)
    4. 标注关键停顿点 [PAUSE]
    5. 标注需要看观众的时刻 [LOOK UP]
    6. 如果页面有数据,用故事化的方式讲解数据

    幻灯片内容:
    {json.dumps(slides, ensure_ascii=False, indent=2)}
    """

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)["notes"]

三、AI 排练辅助

3.1 语速与停顿分析

import librosa
import numpy as np

class SpeechAnalyzer:
    """演讲排练分析器"""

    def analyze_pacing(self, audio_path: str) -> dict:
        """分析语速和停顿"""
        y, sr = librosa.load(audio_path)
        duration = librosa.get_duration(y=y, sr=sr)

        # 使用 Whisper 获取带时间戳的转录
        import whisper
        model = whisper.load_model("base")
        result = model.transcribe(audio_path, word_timestamps=True)

        # 计算语速
        total_words = len(result["text"].split())
        words_per_minute = total_words / (duration / 60)

        # 检测停顿
        pauses = []
        segments = result["segments"]
        for i in range(1, len(segments)):
            gap = segments[i]["start"] - segments[i-1]["end"]
            if gap > 0.5:
                pauses.append({
                    "start": segments[i-1]["end"],
                    "duration": gap,
                    "type": "short" if gap < 2 else "long"
                })

        # 检测填充词
        filler_words = ["嗯", "啊", "那个", "就是", "然后", "对吧", "其实"]
        fillers = []
        for segment in segments:
            for filler in filler_words:
                if filler in segment["text"]:
                    fillers.append({
                        "word": filler,
                        "time": segment["start"]
                    })

        return {
            "duration_minutes": round(duration / 60, 1),
            "total_words": total_words,
            "words_per_minute": round(words_per_minute),
            "pace_assessment": self._assess_pace(words_per_minute),
            "pauses": {
                "total": len(pauses),
                "short": sum(1 for p in pauses if p["type"] == "short"),
                "long": sum(1 for p in pauses if p["type"] == "long"),
            },
            "fillers": {
                "total": len(fillers),
                "per_minute": round(len(fillers) / (duration / 60), 1),
                "top_fillers": self._count_fillers(fillers),
                "assessment": self._assess_fillers(len(fillers), duration)
            },
            "recommendations": self._generate_recommendations(
                words_per_minute, pauses, fillers, duration
            )
        }

    def _assess_pace(self, wpm: float) -> str:
        if wpm < 120:
            return "偏慢 -- 可能显得拖沓,建议加快到 140-160"
        elif wpm < 140:
            return "稍慢 -- 适合严肃话题或非母语受众"
        elif wpm <= 180:
            return "理想 -- 适合大多数演讲场景"
        elif wpm <= 200:
            return "稍快 -- 激情演讲可以,但注意停顿"
        else:
            return "过快 -- 观众可能跟不上,建议放慢并增加停顿"

    def _assess_fillers(self, count: int, duration: float) -> str:
        per_minute = count / (duration / 60)
        if per_minute < 1:
            return "优秀 -- 几乎没有填充词"
        elif per_minute < 3:
            return "良好 -- 偶有填充词,不影响表达"
        elif per_minute < 5:
            return "需改进 -- 填充词偏多,建议用停顿替代"
        else:
            return "严重 -- 大量填充词,严重影响专业感"

3.2 语调与能量分析

def analyze_energy(audio_path: str) -> dict:
    """分析语音能量曲线"""
    y, sr = librosa.load(audio_path)

    # 计算短时能量
    frame_length = int(sr * 0.025)  # 25ms 帧
    hop_length = int(sr * 0.010)    # 10ms 步长
    energy = np.array([
        sum(abs(y[i:i+frame_length]**2))
        for i in range(0, len(y)-frame_length, hop_length)
    ])

    # 归一化
    energy = energy / energy.max()

    # 计算 pitch(基频)
    pitches, magnitudes = librosa.piptrack(y=y, sr=sr)
    pitch_values = []
    for t in range(pitches.shape[1]):
        index = magnitudes[:, t].argmax()
        pitch = pitches[index, t]
        if pitch > 0:
            pitch_values.append(pitch)

    return {
        "energy_profile": {
            "mean": float(np.mean(energy)),
            "std": float(np.std(energy)),
            "dynamic_range": float(np.max(energy) - np.min(energy)),
            "assessment": "单调" if np.std(energy) < 0.15 else "有变化"
        },
        "pitch_profile": {
            "mean_hz": float(np.mean(pitch_values)) if pitch_values else 0,
            "range_hz": float(np.max(pitch_values) - np.min(pitch_values)) if pitch_values else 0,
            "assessment": "平坦" if len(pitch_values) > 0 and np.std(pitch_values) < 30 else "有起伏"
        },
        "recommendations": [
            "在关键论点处提高音量和语调",
            "在数据展示前降低语速、适当停顿制造期待",
            "用语调变化区分不同段落",
        ]
    }

3.3 模拟 Q&A

async def simulate_qa(speech_topic: str, speech_content: str,
                       audience_profile: str, num_questions: int = 5) -> list[dict]:
    """模拟观众提问"""
    prompt = f"""
    你是一位{audience_profile}。你刚听完一场关于"{speech_topic}"的演讲。

    演讲要点:
    {speech_content[:2000]}

    请提出 {num_questions} 个你可能会问的问题,从简单到尖锐排列:
    1. 一个澄清性问题(确认理解)
    2. 一个深入性问题(探究细节)
    3. 一个挑战性问题(质疑观点)
    4. 一个应用性问题(如何实施)
    5. 一个开放性问题(未来展望)

    对于每个问题,提供:
    - question: 问题内容
    - difficulty: easy/medium/hard
    - suggested_answer: 建议回答(200字以内)
    - trap: 这个问题可能的陷阱
    """

    response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)["questions"]

四、现场辅助工具

4.1 实时提词器

class Teleprompter:
    """Web 实时提词器"""

    def __init__(self, script: str, wpm: int = 150):
        self.lines = script.split('\n')
        self.current_line = 0
        self.wpm = wpm

    def get_visible_lines(self, num_lines: int = 5) -> list[dict]:
        """获取当前可见行"""
        result = []
        for i in range(max(0, self.current_line - 1),
                       min(len(self.lines), self.current_line + num_lines)):
            result.append({
                "text": self.lines[i],
                "is_current": i == self.current_line,
                "opacity": 1.0 if i == self.current_line else
                          0.7 if abs(i - self.current_line) == 1 else 0.4
            })
        return result

    def advance(self):
        """前进一行"""
        if self.current_line < len(self.lines) - 1:
            self.current_line += 1

    def retreat(self):
        """后退一行"""
        if self.current_line > 0:
            self.current_line -= 1

4.2 时间管理

class PresentationTimer:
    """演讲时间管理器"""

    def __init__(self, total_minutes: int, slide_count: int):
        self.total_seconds = total_minutes * 60
        self.slide_count = slide_count
        self.start_time = None
        self.slide_times = []

    def start(self):
        self.start_time = time.time()

    def get_status(self, current_slide: int) -> dict:
        if not self.start_time:
            return {"status": "not_started"}

        elapsed = time.time() - self.start_time
        remaining = self.total_seconds - elapsed
        expected_progress = elapsed / self.total_seconds
        actual_progress = current_slide / self.slide_count

        pace = "on_track"
        if actual_progress < expected_progress - 0.15:
            pace = "behind"
        elif actual_progress > expected_progress + 0.15:
            pace = "ahead"

        return {
            "elapsed": self._format_time(elapsed),
            "remaining": self._format_time(max(0, remaining)),
            "pace": pace,
            "pace_message": {
                "behind": f"落后进度,还有 {self.slide_count - current_slide} 页",
                "ahead": "进度超前,可以放慢节奏",
                "on_track": "节奏正常"
            }[pace],
            "slides_remaining": self.slide_count - current_slide,
            "seconds_per_remaining_slide": remaining / max(1, self.slide_count - current_slide)
        }

    def _format_time(self, seconds: float) -> str:
        m, s = divmod(int(seconds), 60)
        return f"{m:02d}:{s:02d}"

五、事后分析

5.1 演讲质量评估维度

维度 指标 数据来源
内容质量 信息密度、逻辑性、数据支撑 转录文本 + LLM 分析
表达质量 语速、停顿、填充词、语调 音频分析
视觉质量 PPT 设计、数据可视化 幻灯片分析
互动质量 观众参与度、Q&A 质量 弹幕/投票/提问
影响力 观点传达率、行动转化率 事后调查

5.2 自动复盘报告

async def generate_postmortem(audio_path: str,
                               slides_path: str,
                               audience_feedback: list[str] = None) -> dict:
    """生成演讲复盘报告"""
    # 1. 语音分析
    pacing = SpeechAnalyzer().analyze_pacing(audio_path)
    energy = analyze_energy(audio_path)

    # 2. 内容分析
    transcript = whisper_transcribe(audio_path)
    content_analysis = await analyze_content_quality(transcript)

    # 3. PPT 分析
    slide_quality = PresentationQualityChecker().check(slides_path)

    # 4. 生成综合报告
    report = {
        "overall_score": calculate_overall_score(pacing, energy, content_analysis, slide_quality),
        "pacing": pacing,
        "energy": energy,
        "content": content_analysis,
        "slides": slide_quality,
        "strengths": [],
        "improvements": [],
        "action_items": []
    }

    # 5. AI 生成改进建议
    recommendations = await generate_improvement_plan(report)
    report["recommendations"] = recommendations

    return report

六、工具生态

工具 功能 适用场景 价格
Otter.ai 实时转录 + 摘要 会议记录 免费/$17/月
Descript 语音编辑 + 填充词删除 演讲后期 $24/月
Yoodli AI 演讲教练 排练反馈 免费/$10/月
Speeko 语音分析 + 训练 个人提升 免费/付费
Prezi AI 动态演示 + AI 辅助 非线性演示 $7-59/月
SpeechFlow 中文 ASR + 分析 中文演讲 按量

总结

AI 辅助演讲的核心价值在于将"感性的演讲艺术"转化为"可量化、可改进的技能指标"。从文稿生成(LLM)、排练分析(语音AI)、现场辅助(提词器/翻译)到事后复盘(多维评估),AI 覆盖了演讲全生命周期。关键实践:用 AI 写初稿但必须个人化改写,用语音分析替代主观感受,用模拟 Q&A 提前准备应变。最终,AI 是工具不是替代——最打动人心的演讲永远来自真实的人。


Maurice | maurice_wen@proton.me