最近 AI 圈太热闹了,Gemini 3 Pro 炸场,谷歌全家桶都成了焦点。我也没忍住,跑去把传说中的 NotebookLM 玩了个遍。
不玩不知道,一玩吓一跳。特别是那个能把任何资料一键变成多人播客的功能,简直是知识搬运工的福音!🎧
像下面这种海报,gemini 是信手拈来
作为一名爱折腾的老程序员,我的第一反应不是“哇,真牛!”,而是“这玩意儿...我好像也能做一个?”
一个更有趣的念头冒了出来:我能不能让 AI 当我的结对编程伙伴,用 AI 来帮我实现这个 AI 功能?
说干就干!
程序员的“执念”:不碰黑盒,只爱源码
一提到“做个东西”,很多人的第一反应可能是 n8n 或 Zapier 这种低代码平台。拖拖拽拽,连接几个 API,一个工作流就搭好了。
这当然很棒,是效率神器。但对于我们这群天天和代码打交道的人来说,总觉得隔了层纱,不够“爽”。我们天生就对“黑盒”有种不信任感,我们想要的是:
- 绝对的掌控力:我想加个重试、换个模型、改个参数,都应该是信手拈来。
- 极致的灵活性:方便调试、易于扩展,未来能把这个小功能无缝集成到更大的系统里。
- “代码母语”的亲切感:我们的思维模式就是函数、模块和逻辑流。
所以,我果断放弃了“连连看”的方案,选择了更硬核、也更有趣的路:邀请我的 AI 编程伙伴 CodeBuddy,用 LangChain(准确地说是 LangGraph)作为“龙骨”,纯代码攒一个出来!
开干!三步“教会”AI 做播客
整个过程出乎意料的顺滑。我基本就是“动动嘴”,把我的想法用大白话告诉 CodeBuddy,它则“动动手”,把逻辑翻译成代码。
第一步:投喂原料——把网页文章“榨成”纯文本 📝
我:“开始吧!第一步,得让它能‘吃’进东西。给我个函数,输入一个 URL,输出干净的文本。”
CodeBuddy 几乎秒回,推荐了 Jina Reader API,干净利落。几行代码,一个 URLExtractor 模块搞定。
为了让大家有更直观的感受,这里我用 TypeScript 和 jsdom 展示一个概念实现:
import { JSDOM } from 'jsdom';
/**
* 从 URL 提取纯文本内容
* @param url 要提取的网页链接
* @returns 网页的纯文本
*/
async function extractTextFromUrl(url: string): Promise<string> {
try {
const response = await fetch(url);
const html = await response.text();
const dom = new JSDOM(html);
// 简单的文本提取逻辑,移除脚本和样式标签
dom.window.document.querySelectorAll('script, style').forEach(el => el.remove());
const body = dom.window.document.querySelector('body');
return body?.textContent || '';
} catch (error) {
console.error('提取文本时出错:', error);
return '';
}
}
第二步:注入灵魂——用 LLM “导演”一场对话 🗣️
这是最关键的魔法。我需要让大模型(LLM)不再是简单的总结,而是化身“编剧”,把一篇平铺直叙的文章,改编成两个主持人的唇枪舌战。
这本质是个 Prompt 设计的艺术。我跟 CodeBuddy 讨论着,一起设计了一个 Prompt 模板,定义了“博学主持人”和“好奇宝宝”两个人设,规定了谈话风格和输出格式。
这个过程特别像在给 AI 导演“说戏” ,告诉他我想要什么感觉的剧情。我只管天马行空地提要求,CodeBuddy 则负责把这些要求转换成严谨的代码结构。
这部分是整个工作流的“大脑”,我们用 LangChain.js 来实现,代码就像在指挥一个剧团:
import { ChatOpenAI } from "@langchain/openai";
import { PromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
/**
* 根据文本内容生成播客脚本
* @param textContent 输入的文本
* @returns 生成的播客对话脚本
*/
async function generatePodcastScript(textContent: string): Promise<string> {
// 定义 Prompt 模板,指导 AI 进行角色扮演和内容生成
const template = `
请将以下文本改编成一期引人入胜的播客。
角色:
- "知识渊博的主持人" (深入浅出,掌控节奏)
- "充满好奇心的搭档" (提出问题,引导话题)
要求:
1. 以对话形式呈现,清晰地标明角色。
2. 风格轻松、有趣,使用口语化表达。
3. 确保对话流畅,逻辑连贯。
原始文本:
---
{content}
---
播客脚本:
`;
const prompt = PromptTemplate.fromTemplate(template);
// 初始化大语言模型
const model = new ChatOpenAI({ temperature: 0.8 });
// 创建处理链
const chain = prompt.pipe(model).pipe(new StringOutputParser());
// 执行链并返回结果
return await chain.invoke({ content: textContent });
}
第三步:开口说话——合成并拼接音频 🎙️
有了剧本,接下来就是把它变成声音。
我:“好了,现在把这些对话文本,分角色变成语音,再拼成一个完整的音频文件。”
CodeBuddy 很快就提供了方案:调用 TTS 服务,然后用 pydub 库来做音频拼接。甚至还贴心地建议在每段对话间加上零点几秒的静音,让节奏更自然。
你看,整个过程,我几乎没怎么被繁琐的 API 调用、异常处理、文件读写给绊住,全程都在享受创造的乐趣。
最后一步是生成音频。我们调用 OpenAI 的 TTS 接口,并给出后续拼接的建议,同样是用 TypeScript 实现:
import fs from 'fs/promises';
import path from 'path';
import { OpenAI } from 'openai';
// 假设已配置 OpenAI API Key
const openai = new OpenAI();
/**
* 将文本转换为语音
* @param text 要转换的文本
* @param voice 使用的语音模型 (alloy, echo, fable, onyx, nova, shimmer)
* @returns 音频文件的 Buffer
*/
async function textToSpeech(text: string, voice: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer'): Promise<Buffer> {
const response = await openai.audio.speech.create({
model: "tts-1",
voice: voice,
input: text,
});
return Buffer.from(await response.arrayBuffer());
}
/**
* 从播客脚本生成完整的音频文件
* @param script 播客对话脚本
* @param outputPath 输出文件路径
*/
async function createPodcastAudio(script: string, outputPath: string) {
// 注意:这只是一个概念性实现。在 Node.js 中拼接音频需要使用 ffmpeg 这样的外部工具库,
// 例如 fluent-ffmpeg。这里为了简化,我们将每个角色的语音分开保存。
const lines = script.split('\n').filter(line => line.trim() !== '');
let part = 1;
for (const line of lines) {
if (line.startsWith('主持人:')) {
const text = line.replace('主持人:', '').trim();
const buffer = await textToSpeech(text, 'nova');
await fs.writeFile(path.join(outputPath, `part_${part}_host.mp3`), buffer);
part++;
} else if (line.startsWith('搭档:')) {
const text = line.replace('搭档:', '').trim();
const buffer = await textToSpeech(text, 'shimmer');
await fs.writeFile(path.join(outputPath, `part_${part}_partner.mp3`), buffer);
part++;
}
}
console.log('音频片段已生成。请使用 ffmpeg 等工具将它们拼接起来。');
console.log(`例如: ffmpeg -i "concat:part_1_host.mp3|part_2_partner.mp3" -acodec copy final_podcast.mp3`);
}
AI 编程伙伴 + LangGraph:为什么是程序员的“梦幻组合”?
跑通整个流程后,我最大的感受是:AI 结对编程,正在彻底改变我们写代码的方式。
- 从“怎么实现”到“做什么”的转变:LangGraph 把工作流变成了清晰的“状态图”,每个节点都是函数,逻辑流转一目了然,完美契合程序员的思维。而 CodeBuddy 则包揽了大量“如何实现函数”的脏活累活,让我能专注于“需要哪些函数”和“它们该如何连接”的顶层设计。
- 掌控感与创造力的双重满足:想换个 TTS 语音?改个函数就行。想增加一个“事实核查”节点?在图里加个节点就好。这种随心所欲的掌控感,是任何图形化工具都给不了的。编程不再是苦差事,而成了一场充满创造力的对话。
写在最后:欢迎来到“对话式编程”时代 🚀
我们正一脚踏入一个“口语化编程”的新纪元。你不再需要精通所有语法和库的细节,你只需要成为一个优秀的设计者和提问者,用自然语言清晰地表达你的构想,AI 就能成为你最强大的“执行官”和“创意伙伴”。
今天我们复刻了一个小小的播客功能,明天就可以用同样的方式,去构建复杂的内部工具、数据分析流程,甚至是自动化交易 Agent。
这,就是我们每个普通开发者都能抓住的,成为“超级个体”的时代机遇。
别再只当一个旁观者了,让我们一起,拿起 AI 这个新武器,去创造真正激动人心的东西!