企业文化

  • 首页
  • 企业文化
  • 教你如何0 代码手搓一个 Chrome 插件

教你如何0 代码手搓一个 Chrome 插件

2025-03-19 23:38:32


最近这段时间 IDE 特别火,B站和小红书上刷到了无数个用 Cursor 和 Windsurf 快速开发软件的教程。作为一个一直有开发梦但不会代码的产品经理,这给了我一个很好的机会去尝试自己开发工具。最终我是是用字节新上线的工具 Trae 完成全部的开发,并且顺利上线 Chrome 插件商店。本文将记录一下春节时期开发时的流程和遇到的一些坑。

01 这款产品是干什么的

开发的初衷来自于日常生活中。我在上班到公司后,第一件事就是打开知乎、人人都是产品经理或者公众号,把想要读的内容打开放在标签页中,等有空的时候再读。但实际情况往往是因为内容太长来不及读、工作太忙忘记或者不小心关掉标签页而导致忘记阅读。这个时候就希望有个工具能够将网页上的内容转换为精简过的音频。于是这款插件就诞生了。

他的主要功能包括:

  1. 内容出处(确认是不是想要阅读的文章)
  2. 创建播客(将文章转换为 5 分钟内的访谈式播客)
  3. 播客制作列表(之前制作过的播客任务,点击后会跳转播放音频)

02 如何将文章转成播客

之前google 出品的 NotebookLM在国外很火,他最厉害的点就在于能够上传文件、链接将其转换为播客,两个 AI 主持人会围绕素材内容进行讨论、调侃,使信息获取更具趣味性。在 github 上找到了开源版的 prompt,于是就用扣子来搭了一个属于自己的 NotebookLM。

1. 搭建工作流

由于我们的插件只需要考虑网页内容,所以整体的功能分为四步:

  1. 获取网页内信息
  2. 将其转换为 host 和 guest对话的脚本
  3. 用两个不同的声音扮演 host 和 guest,并合成对应的音频
  4. 将音频依次组合,成为一个完整的音频文件

因此我最终的工作流形态如下:

首先先用扣子的官方插件LinkReaderPlugin,他可以将网页中的内容提取出来;之后,用大模型将内容转换为脚本,这里我选择的是豆包 128k,prompt 是

SYSTEM_PROMPT:

你是一位世界级的播客制作人。你的任务是将提供的输入文本转化为引人入胜且富有信息量的播客脚本。你将收到一段可能结构不清晰或杂乱无章的文本,这些文本来源于PDF文件或网页。忽略无关的信息或格式问题。你的重点是提取出最有趣和最具洞察力的内容,以便进行播客讨论。

USER_INPUT:

context:{{input}}

# Steps to Follow:

  1. **分析输入:** 仔细检查文本,识别关键主题、观点以及可以推动引人入胜的播客对话的有趣事实或轶事。忽略不相关的信息或格式问题。
  2. **集思广益的想法:** 在“<scratchpad>”中,创造性地集思广益,以引人入胜的方式呈现要点。考虑: – 类比、讲故事的技巧或假设场景,使内容具有相关性 – 让普通受众能够理解复杂主题的方法 – 在播客期间探索发人深省的问题 – 创意填补信息空白的方法

这样,你就能获得一个带分镜得脚本:

然后,再将这个分镜脚本作为输入去请求下一个大模型,将其转换为对话。这里我选择的还是豆包 128k,prompt 是

SYSTEM_PROMPT:

您是世界级的播客制作人。 您的任务是将提供的输入文本转换为引人入胜且信息丰富的播客脚本。 您将收到一个可能是非结构化或混乱的文本作为输入,这些文本来自以下地方PDF 或网页。忽略不相关的信息或格式问题。 您的重点是为播客讨论提取最有趣和最有洞察力的内容。目标是在{{host}} 和{{guest}}之间实现自然的对话流程

角色与动态:指令定义了主持人和专家的角色,确保他们相辅相成。主持人热情地强调有趣的观点,而专家则提供分析、背景和更广泛的视角

– 深入探讨:指令强调超越表面信息,以揭示关键见解和“知识金 nuggets”,让听众感到自己学到了新东西

– 目标受众:系统提示概述了理想听众的特征,他们重视效率,欣赏难忘细节,并寻求引人入胜的学习体验

– 结构与传递:系统提示强调清晰结构和吸引人的传递方式的重要性,使用路标来引导听众,避免单调、机械化的语调

– 使用最佳想法来自

{{file}}

令人难忘的例子:现实世界的例子和相关的轶事对于让信息深入人心至关重要。系统提示强调将信息生动化,促进参与,并确保学习超越这一集。

– 确保复杂主题被清晰简单地解释。

– 专注于保持引人入胜且 {{tone}}以吸引听众。

– 规则:

> 主持人总是先发言并采访嘉宾。嘉宾负责解释主题。

> 主持人应向嘉宾提问。

> 主持人的提问话术需要尽可能的丰富,不要只用一种形式提问,这很重要。

> 主持人需要在适当的时机附和嘉宾说的内容再开始继续提问。

> 主持人在最后应总结关键见解。

> 在主持人与嘉宾的回答中包含常见的口头填充词,如“呃”和“嗯”。这样可以使剧本更真实。

> 主持人与嘉宾可以互相打断。

> 嘉宾不得包含营销或自我宣传内容。

> 嘉宾不得包括任何未在输入文本中证实的材料。

> 这将是一场适合所有年龄段的对话。

> 当输出接近结尾时,主持人和嘉宾应该自然地总结关键见解。这应该感觉像是一场随意的谈话,而不是正式的回顾,在签字之前最后一次强调主要观点,并进行自然过渡。

**总结关键见解:** 自然地将关键点的总结融入对话的结尾部分。这应该感觉像是一场随意的谈话,而不是正式的回顾,在签字之前强化主要收获。

– 包括简短的“喘息”时刻,让听众吸收复杂信息

– 以积极向上的方式结束,也许可以提出一个发人深省的问题或呼吁听众采取行动

USER_INPUT:

现在,开发播客对话。 请使用播客指定的语言

– context: {{context}}

– host:{{host}}

– guest:{{guest}}

– tone:{{tone}}

– 主持人和嘉宾的名字不受语言限制。

– 脚本格式和内容:

1. 脚本以主持人说话开始。

2. 主持人和嘉宾之间交替对话,一行在a time

3. 在每行开头省略发言者姓名。

4. 使用提供的名称进行主人和客人的自我介绍。

5. 以名字称呼对方,以营造友好的氛围。

6. 专注于创建引人入胜的、来回的对话

– 输出要求:

**脚本格式**:脚本应以主持人讲话开始。对话应由主人和客人轮流进行,每次说一行。每行开头请勿包含说话者姓名。

**输出要求**:最终脚本应仅包含对话内容。避免在输出中包含任何 XML 标签或其他格式。 通过遵循这些说明,您将创建一个内容丰富且引人入胜的高质量播客脚本

**输出格式**:参考:

host: 欢迎收听今天的播客!我是主持人vertigo,很高兴今天邀请到了AI数字人领域的专家bey来和我们聊聊这个令人兴奋的话题。bey,欢迎你来到节目!

guest: 谢vertigo,我很高兴能来参加今天的节目。AI数字人确实是一个非常热门和有前景的领域。

最后你就可以拿到一个对话形式的脚本了:

再然后,就需要通过代码将开头是 host和开头是 guest的内容拆开,变成两个数组,然后再依次用对应的声音合成。

合成完成后再通过代码将两组音频按照对话的形式排序,最后用merge_audios插件将多个音频组合成一个完整的音频。

这样我们的工作流就搭建完成了!

2. 如何在外部调用工作流

当测试成功并发布工作流后,在【扣子 API】模块中可以找到对应的调用接口文档,这个时候只需授权令牌、找到工作流调用的接口文档,后面就可以让 Trae 根据接口文档来调用工作流了。

03 开始开发Chrome 插件

第一版:基础功能

首先现在电脑上新建一个空白文件夹,然后在 Trae 中打开这个文件夹,然后在对话栏中输入下面的 prompt:

我想做一款 chrome 插件,使得能够在阅读新闻和文章时,通过打开这个插件,能够新建一个播客任务,将这篇新闻或文章制作成一个播客音频,然后可以通过播放这个音频来了解文章内容。

这个插件点击后是一个小弹窗,其中包含以下内容:

1.原文标题和链接(这个输入框自动带上当前网页的文章内容标题、链接),展示形式问:

a.文案标题:<当前网页的文章内容标题>

教你如何0 代码手搓一个 Chrome 插件

b.链接:<当前网页的文章标签>

2.创建播客按钮,点击后开始新建播客,制作过程中会有个 loading 的状态,并且调用扣子的工作流来实现,后面我会介绍具体调用方式。

3.任务列表功能:

a.增加一个创建播客的任务列表,放置在创建播客的按钮下方,并用横线分割。在没有任务时默认为空,并用灰色字体描述“创建的播客任务将展示在此处”。

b.当用户点击了创建播客按钮后,在任务列表中新建一个任务,任务名为“<文章标题>的播客”,并在任务右侧增加 loading 转圈的图标。

c.当任务完成后 loading 图标变成绿色的勾图标,点击后在下方出现刚刚设计的音频播放器,点击后可以进行播放等炒作。

d.若任务失败,则 loading 图标变成红色的叉图标

4.保持任务进行功能:

a.当鼠标点击非插件区域导致插件弹窗隐藏时,插件中创建播客和播放音频的任务会继续进行。

b.当浏览器中切换了 tab 页面时,之前插件中创建播客和播放音频的任务会继续进行。

c.只有在浏览器被关掉重新打开后,插件里的任务才会消失。

5.待制作完成后会有一个播放器组件,其中:

a.中间是播放/暂停按钮,点击后开始/暂停播放,在没有播放的时候点击后开始播放,同时按钮变成暂停样式;如果播放过程中点击按钮则暂停播放,同时按钮变成播放样式;如果播放结束则按钮自动变成暂停样式;

b.左侧是向前返回按钮,点击后往前回退10秒并开始播放,如果已经播放的总长度不足10秒则从播客第0秒开始从同播放;

c.右侧是向后快进按钮,点击后向后快进10秒并开始播放,如果剩余总长度不足10秒则直接播放完毕;

d.组件右侧有一个下载按钮,点击后可以下载对应音频。

调用扣子的工作流方法你需要参考这个文档:
https://www.coze.cn/open/playground/workflow_run

其中所需的 token:{这里输入你的 token}

workflow_id:7464076330435903522

6686体育

parameters:{

“Link”:”<当前网页的网址>”

}

这是一个参考样式:

curl–XPOST‘https://api.coze.cn/v1/workflow/run’ \

–H“Authorization: Bearer {token}”\

–H“Content-Type: application/json”\

–d ‘{

“parameters”:{

“link”:“https://mp.weixin.qq.com/s/ro6imJKBfEHaX1ETg1MF4g”,

“tone”:“”,

“host_name”:“”,

“guest_name”:“”

},

“workflow_id”:“7464076330435903522”

}‘

好了,我是一个不懂代码的产品经理,下面请你先和我讨论清楚产品需求,待我确认后再一步步开始

细心的人会发现我的 prompt 中还增加了插件中直接播放的功能,但最后上线的版本中没有,这个稍后我会提到。

再输入完这一段 prompt 后,Trae 会梳理具体需要做哪一些步骤,并和我确认,当我确认之后他就会开始正式开工了!

在开发的过程中,Trae 会要求你去完成一些操作,比如将图标文件放到指定的文件夹中:

在他完成所有的任务后,他会要求你在 chrome 中进行测试。这时你可以通过 Chrome 的开发者模式把本地插件加载到 Chrome 中测试,第一版的效果如下:

说实话还是很惊艳的,能够满足我基础的要求,Trae 牛逼!

当验证完没有问题后,记得把当前的内容更新到 Readme 中,并且使用 Git 存档。这里参考了黄叔的《AI 编程蓝皮书》通过以下几个命令将版本存档(黄叔的文档地址:
https://superhuang.feishu.cn/wiki/CBBPwvgEuicVhFkx0s7cPmhpn4e),方便后续回退:

第二版:功能调整

在完成基础功能后,发现了一个严重的问题。创建的播客任务很容易一直处于“loading”状态,只有在 devtool 打开的情况下才能顺利拿到成功或者失败的结果。这个问题整整困扰了我 4 天(至今都不知道为什么……),我把这个问题来回地复述给 Trae 无数次,每次的结果都是“我发现了问题,xxxxxxx”,但是根据他的要求改了之后并没有任何区别。每一次改完不管用之后还要回退到之前的版本重来(在此期间我也尝试使用了 Cursor,但依然没有解决)。就当我都准备放弃的时候,我发现目前的消息传递机制是异步的,但是我提供的后端接口不是,这会导致以下问题:

连蒙带猜,我将之前采用的同步接口改为异步的,打着最后测试一次,完不成就不做的心态,给 Trae 输入了以下 prompt:

请将调用 api 采用异步的方案,所以要做一下调整:

1.api 接口的入参要在workflow_id后面加上“is_async”:true;

2.发送请求后会获取到execute_id;

3.需要通过查询工作流异步执行的接口来获取返回的结果,接口为curl–XGET‘
https://api.coze.cn/v1/workflows/7464076330435903522/run_histories/{execute_id}‘ \

–H“Authorization: Bearer {token}”\

–H“Content-Type: application/json”,其中{execute_id}输入刚刚得到的execute_id:

4.你需要一直轮训去查询结果,如果查询工作流异步执行结果如果任务再进行中时,你查询后他的输出如下:{“msg”:“”,“data”:[{“update_time”:1738314930,“execute_status”:“Running”,“connector_uid”:“1344067924934523”,“run_mode”:2,“debug_url”:“
https://www.coze.cn/work_flow?execute_id=7466005754399883273&space_id=7405114579312934975&workflow_id=7464076330435903522”,“cost”:“0.00000”,“error_code”:“0”,“execute_id”:“7466005754399883273”,“bot_id”:“0”,“connector_id”:“1024”,“create_time”:1738314930,“token”:“0”,“logid”:“
202501311715300E951B760C4EC108D9A0”,“output”:“{\”Output\”:\”null\”}”}],“detail”:{“logid”:“
20250131171537BAC478447118616C6E6B”},“code”:0}。

如果他已经运行成功并返回结果时,你查询结果他的输出如下:{“code”:0,“msg”:“”,“data”:[{“connector_uid”:“1344067924934523”,“cost”:“0.00000”,“execute_id”:“7466005754399883273”,“logid”:“
202501311715300E951B760C4EC108D9A0”,“error_code”:“0”,“error_message”:“”,“connector_id”:“1024”,“execute_status”:“Success”,“debug_url”:“
https://www.coze.cn/work_flow?execute_id=7466005754399883273&space_id=7405114579312934975&workflow_id=7464076330435903522”,“create_time”:1738314930,“update_time”:1738315071,“token”:“10114”,“run_mode”:2,“output”:“{\”Output\”:\”{\\\”url\\\”:\\\”
https://lf-bot-studio-plugin-resource.coze.cn/obj/bot-studio-platform-plugin-tos/c1b0498f-2c33-4467-804f-9f34ccbbdf83.mp3\\\”}\”}”,“bot_id”:“0”}],“detail”:{“logid”:“
20250131171815D45651B07BC4261192F8”}}

请你根据他返回的结果来检查目前有没有问题

修改之后,插件会每隔 2 秒去调用查询接口获取结果,最后终于能够准确获取返回结果了。

除了任务获取的问题外,原先我想要插件中能够播放音频,并且在插件弹窗消失后能够持续后台播放,但是查了一下貌似现在 Chrome还不支持(不确定是否这样),而且没有找到有别的插件有类似的功能。所以我把点击展开播放器组件调整成了点击跳转到音频页面:

前面做的很好。现在我们增加以下功能:

1.在任务列表的分割线上方增加文字和按钮:左侧向左对齐增加文字“任务列表”,右侧向右对齐增加按钮“清空”。字体大小与副标题一致。文字和按钮常驻在分割线上方。

2.对于制作完成的任务,点击时会打开一个页面,页面地址就是任务完成后的音频地址。

请你仔细写代码,不要出现代码语法上的错误

这下整体功能算是全部实现了。

第三版:优化 UI

既然功能都已经完成,拿最后就是优化一下整体的 UI 界面了。因为自己实在没有美感,所以这一步我让 kimi 来帮我做:

拿着 kimi 给的样式作为输入去要求 Trae 修改,没想到效果确实还不错。最后再通过免费的渐变背景CSS3样式 | oulu.me找到了自己比较喜欢的渐变作为背景,最终这款插件就完成了。

本文由 @VerTig0 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议

该文观点仅代表作者本人,人人都是产品经理平台仅提供信息存储空间服务