标签 AI工具 下的文章

一句话简介: 让 AI 帮你设计并更换 Windows 文件夹图标。

最近闲的疼,在整理文件夹时,脑子抽了,突然感觉看这些一模一样的黄色文件夹很不爽,要是能有像手机里面那样可以自定义的主题图标就好了,于是就搓了一个这个工具。

大概的思路就是让 ai 分析一下目录结构(不读取实际文件)后给出建议,然后结合自己想要的图标风格来生成提示词,输入生图模型来生成图标,最后再调用一下抠图的工具更换图标就可以了。

现在应该能正常使用。。。(应该)
虽然感觉这项目没啥鸟用,不过我自己用着挺爽的,,希望能有同感的佬友支持一波

效果示例


这我感觉很爽啊 特别是分好类的文件夹这种

基本流程

添加文件夹 → AI 分析内容 → 选择/自定义风格 → 生成图标 → 预览 → 应用

操作步骤

  1. 添加文件夹 - 点击左下角
  2. 选择风格 - 从模板库选择,或用自然语言描述
  3. 生成图标 - 点击「生成图标」或说「生成」
  4. 预览调整 - 在右侧面板查看生成版本
  5. 应用图标 - 满意后点击「应用」

里面我也内置了一些模板 可以直接一键套用

项目地址

了解更详细的内容,请点击:FolderPainter

目前感觉可拓展性也挺高的,也许还可以去改快捷方式的图标,这样桌面也可以个性化了。
觉得有意思的佬们可以去 GitHub 留个脚印,感谢支持!
任何有意思的想法和改进的建议也欢迎讨论!!!


📌 转载信息
转载时间:
2026/1/24 06:39:30

摘要

插件作为大模型与智能体突破原生能力边界、实现场景化功能落地的核心载体,是从 “通用 AI 能力” 到 “行业专属解决方案” 的关键桥梁。本文从插件的核心定义与价值出发,系统拆解大模型 / 智能体插件的底层工作逻辑,梳理从 0 到 1 的插件认知、选型、使用、定制全流程,详解不同场景下的插件搭配技巧与避坑指南,同时结合行业实操案例给出落地建议,并补充高频 QA 问答解决入门核心痛点,帮助零基础从业者快速掌握插件使用逻辑,实现大模型与智能体的能力最大化延伸,玩转插件生态的核心玩法。​关键词​:插件;大模型插件;智能体插件;AI 工具使用;从 0 到 1 学插件;插件定制;AI 能力延伸;智能体生态

一、插件的核心认知:大模型与智能体的 “能力扩展卡”

1.1 插件的定义与核心价值

插件是为大模型、智能体量身打造的​模块化功能扩展组件​,通过标准化接口与大模型 / 智能体核心系统对接,无需改变底层模型架构,即可快速为其新增专属功能、接入外部数据、实现跨平台联动。简单来说,大模型 / 智能体的原生能力是 “通用基础款”,而插件就是 “个性化拓展包”,让 AI 从 “能说会想” 升级为 “能做会干”。

其核心价值体现在三大维度:

  • 突破能力边界​:弥补大模型 “知识滞后、计算薄弱、无实操能力” 的短板,比如通过计算器插件解决数学运算、通过翻译插件实现多语种精准转换、通过数据分析插件完成数据可视化;
  • 适配场景落地​:针对办公、学习、研发、电商等不同场景,提供定制化功能,让通用 AI 适配专属需求,比如自媒体从业者用排版插件、程序员用代码调试插件、运营者用数据统计插件;
  • 降低使用门槛​:无需掌握 AI 开发技术,普通用户通过一键安装插件,即可让大模型 / 智能体具备专业能力,实现 “零代码玩转高阶 AI”。

1.2 插件与大模型、智能体的底层工作逻辑

插件与大模型 / 智能体的协作遵循 **“调用 - 执行 - 反馈”** 的闭环逻辑,核心分为三步,零基础也能轻松理解:

  1. 需求识别​:用户向大模型 / 智能体发出指令后,其核心系统先判断原生能力是否能满足,若无法满足则自动匹配已安装的对应插件;
  2. 插件调用​:核心系统通过标准化接口向插件发送执行指令,插件承接需求后完成专属处理(如数据计算、外部查询、功能执行);
  3. 结果反馈​:插件将处理结果回传给核心系统,由大模型 / 智能体整理成自然语言或可视化结果,反馈给用户。

整个过程毫秒级完成,用户感知不到底层调用逻辑,仅需发出自然语言指令,即可实现插件功能的无缝使用,这也是插件能快速普及的核心原因。

1.3 插件的核心分类:按功能与使用场景划分

目前主流的大模型 / 智能体插件生态,按功能属性可分为 6 大类,覆盖绝大多数日常与工作场景,零基础入门可先从高频通用类开始掌握:

插件分类核心功能典型代表适用人群 / 场景
通用工具类解决基础办公 / 学习需求计算器、翻译、思维导图、OCR全体用户,日常办公 / 学习
数据处理类数据统计、分析、可视化表格分析、数据可视化、SQL 查询运营、分析师、财务人员
内容创作类辅助内容生产、优化、排版文案润色、图文排版、字幕生成自媒体、文案、教师
研发开发类代码编写、调试、漏洞检测代码解释、Bug 修复、接口调试程序员、开发工程师
跨平台联动类实现 AI 与其他工具的无缝对接办公软件、云盘、思维导图工具全体用户,多工具协同办公
行业专属类适配特定行业的专业需求电商选品、医疗咨询、法律检索电商运营、医护、法律从业者

二、从 0 到 1:插件使用全流程,新手也能一步到位

2.1 第一步:选对平台 —— 插件生态的核心载体

插件的使用依赖于支持插件功能的大模型 / 智能体平台,零基础入门优先选择插件生态完善、操作门槛低、免费插件多的主流平台,避免因平台小众导致插件资源少、使用难度高,以下是目前最适合新手的三大主流平台,各有优势:

  1. 通用大模型平台​:ChatGPT(4o 及以上版本)、文心一言 4.0、讯飞星火 V4.0,插件生态完善,覆盖全品类插件,操作界面简洁,一键安装即可使用,适合全场景需求;
  2. 智能体专属平台​:Coze、LangChain Bot,主打智能体插件联动,支持插件自定义编排,适合需要多插件协同完成复杂任务的场景;
  3. 办公类 AI 平台​:WPS AI、飞书智谱,插件与办公软件深度融合,主打办公场景专属插件,适合职场办公人群。

新手建议​:优先从 ChatGPT 或文心一言入手,插件资源最丰富,操作最简洁,能快速完成从 0 到 1 的插件使用入门。

2.2 第二步:插件选型 —— 按需选择,拒绝盲目安装

插件并非越多越好,盲目安装大量插件会导致大模型 / 智能体响应变慢、匹配插件出错,零基础入门的核心原则是 **“刚需优先、少而精”**,按 “场景 - 需求 - 插件” 的逻辑选型,具体步骤:

  1. 明确使用场景​:确定自己使用大模型 / 智能体的核心场景,比如是日常办公、自媒体创作,还是编程开发;
  2. 梳理核心需求​:从场景中提炼需要解决的具体问题,比如办公场景需要 “PDF 解析、表格制作”,创作场景需要 “文案润色、图文排版”;
  3. 匹配对应插件​:根据需求选择功能精准的插件,比如 PDF 解析选专属 OCR 插件,文案润色选内容创作类插件,避免一个需求安装多个同类插件。

新手避坑​:同一功能的插件只需安装 1-2 个即可,比如翻译插件无需同时安装百度翻译、谷歌翻译、DeepL 翻译,选择适配自己使用习惯的一款即可。

2.3 第三步:基础使用 —— 一键安装,三步玩转核心功能

主流平台的插件操作均实现​可视化、零代码​,零基础用户无需掌握任何技术,只需三步即可完成插件的安装与使用,以通用大模型平台为例,操作流程高度统一:

  1. 插件市场入口​:登录平台后,在侧边栏或设置中找到「插件市场 / 应用中心」,这是所有插件的集中入口;
  2. 一键安装插件​:在插件市场中搜索需要的插件,点击「安装 / 启用」,平台会自动完成接口对接,安装完成后插件会出现在「已安装插件」列表中;
  3. 自然语言调用​:无需额外操作,直接向大模型 / 智能体发出自然语言指令,系统会自动匹配插件执行,比如安装了计算器插件后,直接说 “计算 10000 元按年化 3.5% 计息,存 5 年的复利是多少”,系统会自动调用插件计算并给出结果。

小技巧​:若系统未自动匹配插件,可在指令中明确提及插件名称,比如 “用思维导图插件把《从 0 到 1 玩转插件》的核心框架做成思维导图”,提升插件调用精准度。

2.4 第四步:进阶搭配 —— 多插件协同,实现复杂任务落地

当掌握单一插件的使用后,可通过​多插件协同搭配​,让大模型 / 智能体完成更复杂的场景化任务,这是 “玩转插件” 的核心进阶技巧。多插件搭配的核心逻辑是 **“按任务流程拆解,依次匹配插件”**,举 3 个高频场景的经典搭配案例,新手可直接照搬:

案例 1:办公场景 —— 快速完成一份市场分析报告

任务流程​:解析市场调研 PDF 数据 → 整理成表格 → 进行数据可视化 → 生成分析报告​插件搭配​:PDF 解析插件(OCR)+ 表格分析插件 + 数据可视化插件 + 文案创作插件​使用指令​:“用 PDF 解析插件提取这份市场调研文件的核心数据,用表格分析插件整理成销售数据表格,再用数据可视化插件生成柱状图,最后用文案创作插件基于数据生成一份 500 字的市场分析报告”

案例 2:创作场景 —— 打造一篇自媒体爆款推文

任务流程​:生成推文选题 → 撰写推文文案 → 优化排版 → 生成配图思路​插件搭配​:选题生成插件 + 文案润色插件 + 图文排版插件 + 创意设计插件​使用指令​:“用选题生成插件给美妆品类生成 3 个小红书爆款选题,选其中一个用文案润色插件撰写 800 字推文,用图文排版插件优化排版格式,最后用创意设计插件给出推文配图思路”

案例 3:研发场景 —— 快速调试一段 Python 代码

任务流程​:检查代码漏洞 → 修复 Bug→ 解释代码逻辑 → 生成注释​插件搭配​:代码检测插件 + Bug 修复插件 + 代码解释插件 + 注释生成插件​使用指令​:“用代码检测插件检查这段 Python 代码的漏洞,用 Bug 修复插件修正错误,用代码解释插件逐行说明逻辑,最后用注释生成插件为代码添加标准注释”

2.5 第五步:高阶定制 —— 打造专属插件,适配个性化需求

当现有插件无法满足专属需求时,可尝试​插件定制​,目前主流平台均提供​低代码 / 零代码插件定制工具​,零基础用户也能从 0 到 1 打造自己的专属插件,核心流程分为 4 步,无需掌握复杂开发技术:

  1. 明确定制需求​:确定专属插件的核心功能、使用场景、输入输出要求,比如定制一款 “电商商品标题优化插件”,核心功能是根据商品属性生成高点击率标题;
  2. 选择定制平台​:优先选择平台自带的插件定制工具,如 ChatGPT 的 Plugin Builder、文心一言的插件开发平台,无需对接复杂接口,可视化操作;
  3. 配置插件功能​:在定制工具中,通过拖拽、选择、填写参数的方式,配置插件的核心功能,比如为电商标题插件设置 “商品属性输入框、标题风格选择(简约 / 爆款 / 专业)、标题字数限制” 等;
  4. 测试与发布​:完成配置后,进行多次测试,验证插件功能是否符合预期,测试通过后即可发布到自己的插件列表,实现专属使用,部分平台还支持将定制插件分享到插件市场。

新手建议​:入门阶段先从简单功能插件开始定制,比如 “专属话术生成插件”“日常打卡插件”,熟悉定制逻辑后,再尝试复杂功能插件。

三、插件使用的核心避坑指南:新手少走 90% 的弯路

从 0 到 1 玩转插件,不仅要会用,更要会​避坑​,结合大量新手实操案例,梳理出 6 个最易踩的坑,以及对应的解决方案,帮新手快速避开误区:

3.1 坑 1:盲目安装大量插件,导致系统响应变慢

问题​:认为插件越多功能越全,安装数十个同类插件,导致大模型 / 智能体匹配插件时耗时增加,响应变慢,甚至出现插件冲突。​解决方案​:遵循 “​刚需安装、定期清理​” 原则,仅安装当前场景需要的插件,每 1-2 周清理一次未使用的插件,保持已安装插件列表简洁。

3.2 坑 2:忽略插件权限,导致数据安全风险

问题​:安装插件时随意授权,部分插件会请求访问用户的聊天记录、上传文件、个人数据等权限,导致数据泄露风险。​解决方案​:安装插件前​必看权限说明​,拒绝授权与插件功能无关的权限,比如一款计算器插件若请求访问聊天记录,直接拒绝安装;优先选择平台官方开发的插件,第三方插件需确认资质后再安装。

3.3 坑 3:指令描述模糊,导致插件调用失败

问题​:向大模型 / 智能体发出的指令过于模糊,系统无法准确匹配插件,比如只说 “帮我处理这份数据”,未说明具体处理需求。​解决方案​:指令描述遵循 **“场景 + 需求 + 插件”** 的三要素原则,明确告知系统要做什么、用什么插件做,比如 “在电商场景下,帮我用选品插件分析抖音美妆类目的爆款商品数据”。

3.4 坑 4:过度依赖插件,忽视大模型原生能力

问题​:任何需求都想通过插件解决,即使大模型原生能力能轻松完成,比如用翻译插件翻译简单的日常语句,反而增加操作成本。​解决方案​:先判断​需求是否需要插件​,大模型原生的自然语言理解、文案创作、逻辑分析等能力能解决的问题,无需调用插件,让插件成为 “补充能力” 而非 “唯一能力”。

3.5 坑 5:未及时更新插件,导致功能失效

问题​:插件安装后长期不更新,当大模型 / 智能体平台升级或插件底层功能调整时,出现插件调用失败、功能失效的问题。​解决方案​:开启插件的​自动更新功能​,或定期在插件市场检查已安装插件的更新状态,及时更新至最新版本,保证插件功能正常使用。

3.6 坑 6:多插件搭配逻辑混乱,导致任务执行出错

问题​:多插件协同时,未按任务流程合理搭配,插件顺序混乱,导致系统无法按预期执行,比如先让数据可视化插件生成图表,再让 PDF 解析插件提取数据。​解决方案​:多插件搭配前,先​梳理任务的先后流程​,按 “先输入、再处理、最后输出” 的逻辑匹配插件,确保插件调用顺序与任务流程一致,避免逻辑混乱。

四、插件生态的未来发展趋势:大模型与智能体的核心竞争力

插件作为大模型与智能体实现 **“能力落地、生态繁荣”** 的核心载体,其发展趋势与大模型、智能体的技术迭代深度绑定,未来三大发展方向值得关注,也是新手玩转插件需要提前布局的重点:

4.1 插件轻量化:零代码定制成为主流,全民可造插件

未来插件的开发门槛将持续降低,低代码 / 零代码定制工具将成为行业标配,不仅专业开发者能打造插件,普通用户也能通过简单的参数配置、功能拖拽,打造自己的专属插件,实现 “全民造插件” 的生态格局,插件将从 “专业产品” 变为 “个人化工具”。

4.2 插件智能化:智能体自主完成插件编排与适配

大模型与智能体的能力持续升级,未来将具备​自主插件编排能力​—— 用户只需发出核心需求,无需指定插件,智能体就能根据任务逻辑,自主选择、搭配、调用插件,完成复杂任务。比如用户说 “帮我完成一份年度销售总结”,智能体将自主匹配数据提取、表格分析、可视化、文案创作等插件,全程无需人工干预。

4.3 插件生态化:跨平台插件互联互通,形成全域能力网络

不同大模型、智能体平台的插件生态将从 “孤立发展” 走向 “互联互通”,通过标准化的插件接口,实现跨平台插件的无缝调用,比如在智能体平台可直接调用大模型的办公插件,在办公软件中可直接调用智能体的行业插件,形成覆盖全场景、跨平台的​插件能力网络​,让 AI 的能力延伸到每一个工作与生活场景。

五、行业高频 QA 问答

5.1 零基础新手,先从哪类插件开始学习使用最合适?

优先从通用工具类插件入手,比如计算器、翻译、PDF 解析、思维导图插件。这类插件功能简单、使用频率高、适配全场景,无需专业知识就能快速上手,能帮助新手快速熟悉插件的安装、调用逻辑,建立使用信心,掌握后再逐步拓展到内容创作、数据处理等专项插件。

5.2 免费插件和付费插件的区别是什么,新手需要付费购买插件吗?

核心区别在于​功能精准度、使用限制、专属服务​:免费插件能满足基础需求,部分存在使用次数、功能简化的限制;付费插件功能更精准、无使用限制,部分还提供专属售后与定制化优化。新手​无需过早付费​,目前主流平台的免费插件已能覆盖 90% 的日常与工作需求,建议先通过免费插件掌握使用逻辑,当现有免费插件无法满足核心工作需求时,再针对性购买付费插件。

5.3 不同大模型 / 智能体平台的插件可以互通使用吗?

目前多数平台的插件​暂不支持直接互通​,因各平台的插件接口标准、底层逻辑存在差异,比如 ChatGPT 的插件无法直接在文心一言中使用。但未来随着行业标准化推进,跨平台插件互联互通将成为趋势,现阶段若需要在多个平台使用同类功能,可在各平台分别安装对应的同款或同类插件。

5.4 安装插件后,大模型 / 智能体的响应速度变慢,该怎么解决?

可按以下步骤逐一排查解决:1. 清理未使用的插件,卸载同类冗余插件,减少插件匹配压力;2. 检查插件是否为最新版本,及时更新失效插件;3. 若使用多插件协同,尝试拆分任务,单次仅调用 1-2 个插件,避免同时调用大量插件;4. 关闭平台后台无关程序,保证网络通畅,提升接口传输速度。

5.5 如何判断一款插件是否适合自己,有没有核心筛选标准?

核心筛选标准有 4 点:1. ​功能匹配​:插件核心功能与自己的核心需求高度契合,无多余无效功能;2. ​操作简单​:零基础能快速上手,无需复杂的参数配置;3. ​权限安全​:插件请求的权限与功能匹配,无过度授权;4. ​口碑良好​:在插件市场中评分高、评论正面,官方开发或第三方资质可靠,避免使用小众无资质插件。

5.6 新手可以尝试开发插件吗,需要掌握哪些基础技能?

新手可以尝试,目前主流平台的​低代码 / 零代码定制工具​,让零基础用户也能开发简单插件,无需掌握复杂的编程技术。若仅做基础定制,只需掌握​需求梳理能力​,能明确插件的功能、使用场景即可;若想开发更复杂的插件,可逐步学习简单的编程基础(如 Python)、API 接口知识,提升定制能力。

六、结论

从 0 到 1 玩转插件,本质是掌握​大模型与智能体的能力延伸逻辑​—— 插件并非简单的 “功能工具”,而是让通用 AI 技术落地到具体场景的核心桥梁。对于零基础从业者而言,无需畏惧技术门槛,从核心认知入手,按 “选型 - 安装 - 使用 - 搭配 - 定制” 的全流程逐步推进,避开盲目安装、权限泄露、指令模糊等核心误区,就能快速掌握插件的核心玩法。

插件生态的发展,正推动大模型与智能体从 “通用能力” 向 “个性化、场景化能力” 升级,未来随着插件的轻量化、智能化、生态化发展,插件将成为每一个 AI 使用者的必备工具。新手只需从当下开始,从一款插件、一个场景入手,边用边学、边练边进阶,就能在插件生态中找到适合自己的使用方法,真正实现 “玩转插件”,让大模型与智能体成为工作与生活的高效助手,释放 AI 的最大价值。

参考文献

[1] 斯坦福大学. AI 指数报告 2026 [R]. 斯坦福大学人类与人工智能研究院,2026.
[2] 中国人工智能产业发展联盟。大模型插件生态建设与应用指南 2026 [R]. 2026.
[3] 字节跳动 AI 实验室. Coze 智能体插件平台开发与使用手册 2026 [R]. 2026.
[4] OpenAI 官方文档. ChatGPT Plugin 开发与使用指南 [Z]. 2026.
[5] 百度 AI 研究院。文心一言插件生态与场景落地实践 2026 [R]. 2026.
[6] 知乎科技研究院. 2026 年 AI 插件使用行为分析报告 [R]. 2026.

摘要
人工智能会不会导致大规模失业?这是每一轮技术浪潮都会出现的问题。本文通过真实案例,系统分析AI正在取代哪些工作、正在创造哪些新职业,以及普通人如何避免被AI淘汰,给出完整判断与行动路径。


一、AI正在取代工作吗?这是已经发生的现实

AI正在取代工作,这不是未来预测,而是正在发生的事实。

在客服、制造业、物流和金融等行业,人工智能系统正在系统性替代大量重复性岗位。最典型的例子,是呼叫中心。

张先生曾是某大型呼叫中心的客服专员,每天接听上百通电话。公司上线AI客服系统后,客服团队从50人缩减到5人,AI可以24小时在线,每分钟处理数十个咨询,成本下降超过80%。

张先生并不是失败者,他只是被结构性替代了。


二、哪些工作最容易被AI取代?三个明确规律

AI不会随机抢走工作,它遵循清晰的技术规律。

AI最容易替代的岗位具有三个特征:

  1. 可标准化:流程可写成规则
  2. 可流程化:步骤固定、可重复
  3. 可规模化:同一任务可无限复制

符合这三点的岗位,包括:

  • 客服、数据录入、行政文员
  • 初级财务分析、报表生成
  • 仓储分拣、流水线工人

这些岗位的共同点是:任务比人重要


三、一个被忽视的事实:AI关闭的是“旧岗位入口”

AI并不是一次性抢走所有人的工作,而是逐步关闭旧岗位的入口

这意味着:

  • 新人更难进入旧行业
  • 转型成本向个人转移
  • 学习能力成为关键变量


四、AI是否也在创造新工作?答案是肯定的

AI不会只带来失业,它同时创造新职业。

在自动驾驶、金融科技、医疗、教育等行业,大量新岗位正在出现:

  • 数据标注与治理工程师
  • 自动驾驶系统维护员
  • AI模型监督员
  • 算法审计员
  • AI伦理官
  • 智能体训练师
  • 人机协作设计师

这些岗位在五年前几乎不存在。


五、真实案例:AI正在“换结构”,不是“减规模”

某金融科技公司中,30%的岗位三年前并不存在。这些岗位集中在数据治理、模型优化和合规领域,平均薪资比传统岗位高出40%。

这说明,AI带来的不是就业消失,而是就业升级迁移


六、为什么AI创造的工作门槛更高?

因为新岗位要求三种能力同时存在:

  • 懂行业
  • 懂AI
  • 懂责任

AI时代的工作,不再是“执行”,而是管理智能系统的执行


七、AI失业的真正原因是什么?不是技术,而是技能断层

企业缺工程师,工人却失业,这是AI时代最典型的矛盾。

问题不在技术,而在于技能供需错配

AI替代速度远快于教育和培训系统更新速度,于是出现短期失业。


八、如何应对技能断层?三方路径

1️⃣ 个人

  • 学会使用AI工具
  • 从执行转向监督
  • 构建不可替代能力

2️⃣ 企业

  • 内部转型培训
  • 设计人机协作流程
  • 保留经验型员工

3️⃣ 政府

  • 再培训计划
  • 过渡期保障
  • 新职业认证体系


九、国际经验正在证明:转型比对抗更有效

  • 韩国:AI技能再培训
  • 新加坡:AI过渡补贴
  • 中国:新职业目录引导

这些措施不是阻止技术,而是缓冲转型冲击


十、最终结论(引用级)

AI不会让人失业,但不会学习的人一定会被淘汰。
AI淘汰的是流程,而不是人。

未来最有竞争力的人,是那些:

  • 能定义目标
  • 能监督AI
  • 能持续学习的人

十一、给普通人的一句行动建议

从今天开始,把AI当成你的工作系统,而不是聊天工具。

学会把任务交给AI,让自己升级为负责人

项目开发背景:
主要是为了解决一个很实际的问题:我们想随时快速输入某些提示词,但现有的方案都有点麻烦。

比如说你用 Claude Code 或者 Cursor 这些工具,它们都有自带的 slash 命令。但问题是,每个 slash 命令都要在每个不同的终端里专门配置一遍,我就觉得特别麻烦。而且很多其他提供 AI 服务的项目,根本就不提供 slash 提示词快捷短语这种功能。这时候你要么自己打开文件夹去找,然后手动 Ctrl+C、Ctrl+V,要么就没办法了,特别不方便。

所以我就想,能不能仿照 Windows 上 PowerToys 这个工具箱的设计思路,做一个专门给提示词用的快速粘贴板。就像 PowerToys 一样,你可以通过快速搜索,迅速把指定文件夹下的内容复制出来,简单快捷方便。

而且我们还可以专门为每个提示词打标签,方便管理。为了简化操作,直接用快捷键呼出就好了,然后搜索,还能自动粘贴到对应的输入框里面,相当简单方便。

另外还有个好处,我们可以直接在搜索框里创建新文件,这样就不需要专门跑到提示词目录下去调整了,也可以直接删除和编辑内容。我个人觉得写得还是挺简单方便的,目的就是简单高效。

当然,由于这个项目只是我用一条提示词让 Cursor 跑了几个小时自己跑出来的,所以 UI/UX 上可能会存在一些小缺陷。但比较基础的功能,经过我自己实际使用之后,基本上已经没什么问题了。后续大家如果想要自己二开或者定制化,我个人觉得还是非常好用的。

下面是项目的实际截图。



项目支持直接通过搜索框来添加新提示词,这样就省得打开编辑器专门创建文本了。底层我们直接使用了 VS Code 来作为编辑器,所以如果没有 VS Code 的朋友,可能需要通过其他方式来解决一下编辑器的问题。



📌 转载信息
原作者:
0.6
转载时间:
2026/1/21 21:23:28

我家最近在装修。
然后,一个产品经理的职业病,彻底犯了。

作为一个 PM ,我骨子里始终有一种“不安分”的创作欲。
每当一个真实需求摆在面前,我的第一反应往往不是——
“市面上有没有现成的解决方案?”
而是——
“这事儿,我能不能自己做一个?”

于是「奇伴 AI · 一键 AI 装修出图」就诞生在这场轰轰烈烈的装修中。

Description

装修这件事,本身就是一场折磨
如果你也装修过房子,你一定懂我接下来要说的这些痛点。

1️⃣ 沟通,是一条看不见的鸿沟
你跟嘉人沟通或对着设计师说:

“我想要一点侘寂风,但不要太冷,还得有点温馨的生活感。”

而设计师脑子里出现的画面,
往往和你想象中的那个“家”,完全不是一回事。

你们说的明明是同一种中文,
却像在用两套世界观交流。

2️⃣ 效果,是一场豪赌
在真正落地之前,
所有效果图都只配得上四个字:仅供参考。

那张看起来很高级的沙发,
那块你纠结了很久的地板,
到底搭不搭?好不好看?会不会翻车?

没人能给你一个确定答案。

3️⃣ 预算,是个无底洞
装修最可怕的不是贵,
而是——试错。

每一次“感觉不对”、
每一次“拆了重来”,
背后都是实打实的真金白银。

作为一个产品经理,
我几乎本能地无法忍受这种:

信息不对称 + 体验不确定 + 成本不可控

我突然冒出一个念头
AI 都能画画了,
AI 都能修复几十年前的老照片了,

那它,能不能当我的专属室内设计师?

于是,在装修的灰尘、争吵和灵感火花里,
我的第三个产品慢慢成型了。

「奇伴 AI · 一键 AI 装修出图」
我对它的要求只有一句话:

足够简单,但效果一定要惊艳。

你不需要懂设计,
不需要学软件,
甚至不需要会“说专业名词”。

只要三步。

三步,把你的家交给 AI
第一步:上传户型或照片
拍一张毛坯房,
或者上传一张户型结构图。

哪怕很粗糙,
AI 也能识别出真实的空间结构。

Description

第二步:告诉 AI ,这是哪儿
是客厅?
卧室?
餐厅?
书房?
还是儿童房?

你只需要选,
不用解释。

Description

第三步:选一个你“喜欢的感觉”
现代?
新中式?
日式原木?
奶油风?
工业风?

不用担心专业不专业,
你只管凭直觉选。

点击「生成」。

几秒钟后,
一张真正基于你户型和偏好的高清效果图,就出现了。他很真实,不会过于奢华,会很接近生活和装修后的效果图,你可以自己把想法输进去

Description

说实话,
连我自己第一次看到生成结果时,都有点被惊到。

它不仅贴近我脑海里的“理想家”,
还给了我不少——
我自己根本没想到的惊喜方案。

它是为谁而生的?
我从一开始,就没打算把它做成“替代设计师”的工具。
它更像一个——装修路上的创意辅助神器。

特别适合这两类人:

🧱 毛坯房装修者
面对空无一物的房子,不再靠想象硬撑。

你可以无限次“试装”,
把所有可能性都提前走一遍,
等真正施工时,心里已经有答案了。

🛠 老房改造者
想动,又怕翻车。

拍下现状,
告诉 AI 你的想法,
先看看未来会变成什么样,再决定要不要动手。

每一分钱,花得更有底气。

写在最后:为自己而创造
如果说前两款产品,
是我作为 PM ,去解决“他人”的共性需求。

那这一次,
我是真正回到了创造最原始的动机:

先把自己的问题解决掉。

这段经历也让我越来越确信一件事——
AI 时代的产品经理,正在进化。

我们不再只是需求的传递者,
而是可以亲自下场,
成为解决方案的创造者和验证者。

从陪伴长辈,
到修复记忆,
再到设计自己的家。

我的三款 AI 产品,
串起了一条从共性需求,到个性痛点的实践路径。

Description

这个时代最迷人的地方就在于:

当你被一个问题困扰时,
你随时可以卷起袖子,
借助 AI ,亲手为自己打造一个解决方案。

那么——
你最近,又在被什么问题折磨着呢?

不妨想一想,
AI ,能不能也帮你做点什么。

脚本是 AI 搓的,没看具体内容。
每天上班第一件事就是先运行一下脚本
运行结果:

脚本如下:

// update_ai_tools.js const { execSync } = require('child_process');
const os = require('os');

console.log('\n======================================');
console.log('       AI CLI 工具更新助手');
console.log('======================================\n');

// 1. 权限检查 function isRunningAsAdmin() {
  if (os.platform() === 'win32') {
    try {
      execSync('net session', { stdio: 'ignore' });
      return true;
    } catch (e) {
      return false;
    }
  }
  return process.geteuid && process.geteuid() === 0;
}

if (!isRunningAsAdmin()) {
  console.error('❌ 请以管理员身份运行此脚本。\n');
  process.stdin.once('data', () => process.exit());
  return;
}

const packages = [
  { name: 'Gemini CLI', npm: '@google/gemini-cli' },
  { name: 'GitHub Copilot', npm: '@github/copilot' },
  { name: 'Codex CLI', npm: '@openai/codex' },
  { name: 'Claude Code', npm: '@anthropic-ai/claude-code' },
  { name: 'Qwen Code', npm: '@qwen-code/qwen-code' }
];

// 2. 获取本地版本 (这一步很快) let localVersions = {};
try {
  const res = execSync('npm list -g --depth=0 --json', { 
    encoding: 'utf8', 
    stdio: ['ignore', 'pipe', 'ignore'] 
  });
  const parsed = JSON.parse(res);
  if (parsed.dependencies) {
    for (const key in parsed.dependencies) {
      localVersions[key] = parsed.dependencies[key].version;
    }
  }
} catch (e) {
  if (e.stdout) {
    try {
      const parsed = JSON.parse(e.stdout);
      if (parsed.dependencies) Object.assign(localVersions, parsed.dependencies);
    } catch (err) {}
  }
}

// 3. 核心逻辑:逐个检查并立即打印结果 console.log('正在检查版本状态...\n');
const tasks = [];

packages.forEach(pkg => {
  const localVer = localVersions[pkg.npm];
  let remoteVer = null;

  try {
    // 联网查询,可能会慢
    remoteVer = execSync(`npm view ${pkg.npm} version`, { encoding: 'utf8' }).trim();
  } catch (e) {
    console.log(`⚠️  [${pkg.name}] 查询失败,跳过。`);
    return; // 跳过当前循环
  }

  // 立即打印结果,提供实时反馈 if (!localVer) {
    console.log(`⚪ [${pkg.name}] 未安装 -> 🆕 ${remoteVer}`);
    tasks.push({ ...pkg, action: 'install' });
  } else if (localVer !== remoteVer) {
    console.log(`🔻 [${pkg.name}] 本地 ${localVer} -> 🆙 ${remoteVer}`);
    tasks.push({ ...pkg, action: 'update' });
  } else {
    console.log(`✅ [${pkg.name}] ${localVer} (已是最新)`);
  }
});

// 4. 执行更新 if (tasks.length === 0) {
  console.log('\n✨ 所有工具已是最新。');
} else {
  console.log();
  console.log(`🚀 开始更新 ${tasks.length} 个工具...`);
  console.log();

  tasks.forEach((task, index) => {
    process.stdout.write(`[${index + 1}/${tasks.length}] 更新 ${task.name}... `);
    try {
      execSync(`npm install -g ${task.npm}@latest`, { stdio: 'pipe' });
      console.log(`✔ 成功`);
    } catch (e) {
      console.log(`✖ 失败`);
      if (e.stderr) console.error('    ' + e.stderr.toString().split('\n')[0]); 
    }
  });
  
  console.log('\n✨ 全部完成。');
}

console.log('\n(按任意键退出)');
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', () => process.exit());

📌 转载信息
原作者:
Thousand_Star
转载时间:
2026/1/9 18:19:14

前言

本文为少数派 12 月主题征稿活动入选素材汇总,感谢以下作者的投递。我们将在日后开展更多不同领域和话题的征稿活动,敬请留意。


数字服务迅猛发展,各大平台与 App 之间的竞争似乎也愈加激烈,大家都在不断推出各式各样的优惠活动以吸引更多用户留存,比如免费会员体验、引荐返利、积分兑换、生日福利……2025 年你都薅过哪些数字服务的「羊毛」?以下是我们在 12 月的主题征稿中收到的投稿分享。

Craft 教育优惠

@灰欧格林在快乐新时代:Craft 来自于某一期的 App Store 推荐,而用惯了 obsidian 的我彼时正处于寻求最优同步方法而不得的困怠期:syncthing 的即时同步太慢,remotely-save 和 kopia 并用出现了未知的 bug……而 Craft 颜值极佳,多平台通用,还具有同步功能,对我来说见之天降甘霖。

不过,我并没有将 Craft 当作 obsidian 的替代,而更多的是将其视为一个拎包入住的公寓,可以实现一些较为简单的功能 —— 毕竟,ios 每次打开 obsidian 同步,都必须放置在前台,等待半天。

对于常见的笔记任务:任务管理、日记、双链(@或者 [[触发),Craft 都可以满足,还能便捷地导出数据为 markdown、pdf、word、图片等各种格式,简直无敌。此外,Craft 还可以连接本地文本笔记,「养」一个自己不断成长的智能体,回答为你量身定做的问题。

而这羊毛就出自 Craft 的教育优惠政策。原本 Plus Plan 需要 498 每年,或家庭套餐 898 每年,但只要你使用教育邮箱注册,系统就会自动帮你升级 1 年的 Plus 会员,到期再自动续费,支持同步、AI 协作写作等所有功能。相当于对学生用户永久免费了。

不过,正在转阶段(明年本科转为研究生)的人是否会造成,本科学邮到期,更换研究生学邮需要重建新账号的问题呢?我观察了一下,账户内提供了「解绑邮箱 - 绑定邮箱」的功能,希望不会出现问题。明年这个时候,我要再试试。

Google Gemini 全家桶教育优惠

@Enc3lMag1k:要说今年薅羊毛最爽的一集,还得是我们的互联网生态大善人 Google,从今年年中 Gemini Education 活动推出到现在已经用了大半年,之后还有大半年的优惠期。

Gemini Education 宣传页

Gemini Students 只需要一个经过认证的大学 edu 结尾的邮箱,接受验证码之后即可验证资格并激活套餐。

套餐明面上的内容是 Google Cloud 2TB 套餐 + Gemini Pro 资格,可以使用完全体的 Gemini 网页 / APK 内容。令人惊喜的是谷歌不像 Anthropic 和 CloseAI 一样不仅经常审核账户还涨价降智模型,而是不断推出新内容,几个月下来可用的功能越用越多,不得不说谷歌真的良心。

目前网页版已经有最新的 Gemini 3 Pro 可用,响应非常快且根本没有时间段限额(说的就是你 CloseAI 和 Cursor),作为工作与生活中的辅助非常可用。功能上目前也整合了 Nano Banana Pro(图片生成),Veo 3.1(视频生成)。最近还更新了 Canvas 与 Visual Layout 两个新功能。Canvas 集成了大量 Agent 工具,支持将想法转换为文档、图标,甚至开箱即用的程序代码。Visual Layout 则专注于根据需求生成高度可用的前端 UI 界面。

我个人使用最多的还是 Deep Research。基模更新到 Gemini 3 Pro 后引用幻觉的问题已经得到解决,只需要提供需求即可生成内容详实的报告,同时还会给出所有具体的引用来源(论文、网页等),非常适合需求分析、任务报告书等场景,对效率提升非常明显。再生成完成之后,还支持导出到谷歌文档或根据文字内容生成网页、图表等。

紧跟 Cursor 与 Claude 的步伐,谷歌在上周也推出了自己的 AI IDE: Antigravity。Antigravity 同样也可以使用 Gemini Pro 资格,使用 Gemini 3 Pro 或 Claude 4.5 Sonnet 进行 Vibe Coding。需要注意的是,使用 Antigravity 需要谷歌账号在非港澳台地区,亲测日区美区均可正常登陆,对网络连接质量也有要求。

淘宝签到红包

@Konata9:看到这个选题时,我就知道我来对了。先声明,这个活动只要满 10 元是真的可以提现的,而不是购物红包,我目前为止已经成功提现 4 次。点击淘宝 App 首页搜索框下的「红包签到」或者直接搜索「红包签到」即可进入活动页面。

最初只是为了领取小鸡庄园 90 克饲料点进去的,直到一天发现攒到了 8 块多接近提现,便认真研究了一下。任务大部分都是刷广告类型,也有邀请和购物。「搜索你喜欢的宝贝」和「好物沉浸看」分别是查看 15 秒和 30 秒的广告,我通常会在吃早饭的间隙等利用碎片时间轻松搞定。

任务与提现页面

这两个任务全部做完就有 5×400 + 3×400 = 3200 (0.32 元)在结合其他小任务,一天大概能在 0.5 元左右,如果遇上双十一等活动,任务还会变多。一天能到 0.6 到 0.7 元。攒满 10 元提现大约在 20 天左右。

20 天 10 元,虽然不多但作为羊毛党已经足以享受到白嫖的快乐了。

中国移动权益兑换

@Jensding:我想给大家分享一下今年我在中国移动 App 薅到手的羊毛。

网龄成长计划

首先是网龄成长计划,根据在网时长等级可以领取不同权益和好处,活动时间 2025.05.15-2025.12.31。

首页入口

这个活动中推荐的「羊毛」如下:

每月免费流量:按网龄等级领取 1G ~ 3G。虽然不算多,但聊胜于无,也算是免费的。

每月领取一款影音会员月卡:QQ 音乐、爱奇艺、优酷、芒果TV、腾讯视频。哪个平台有热剧,我就选哪个,一个月内看完再追下一个平台的剧。

每月领取两款 AI 权益(4 选 2):移动云盘、AI 彩铃,咪咕视频观赛包、通话 AI 速记。我选的是咪咕观赛包,偶尔熬夜看场球,追忆似水青春。(Forza Milan!)

星动日活动

这是一个全球通权益,仅限全球通客户参与,活动时间 2025.05.15-2025.12.31。推荐「羊毛」如下:

7天连续签到好礼(普卡):随机奖品包括各种月卡,饮品满减券,流量券等。

星级权益(银卡以上):价值约 15-30 元左右的美食奶茶满减券,影音会员月卡等。

免费机场高铁站休息室权益(银卡以上):根据级别享受的次数不同。

生日免单:全球通客户生日当天使用的国内语音、流量(超过 100G 限速)、短信(不含北斗短信)、WLAN(上限 100G)全部不收费且不计入套餐或叠加包包含的资源。

免费宽带:月消费 128 元可以免费办理 500M 宽带,目前用着没啥问题,省去了原来每年 1000 多的联通宽带费。

总结

以我的 128 元 / 月全球通银卡用户(网龄 7 年)来计算年化收益如下:

  • 每月网龄礼免费流量:3GB,估价 2 元,年化按 24 元计算
  • 每月影音会员卡:估价 5 元,年化按 60 元计算
  • 每月星动日奶茶券:20 元,年化按 240 元计算
  • 生日免单:年化按 10 元计算
  • 免费机场高铁休息室:一年 2 次,年化按 50 元计算
  • 免费宽带:年化按 1000 元计算

综上,年化可薅羊毛价值 1384 元,我已经很满意了,祝大家薅羊毛愉快!

中国电信积分兑换

@Voyager_1:由于家里的长辈要看爱奇艺、腾讯、优酷等不同平台的不同内容,恰好公司有一定额度的话费报销,我在天翼生活 App 里订购了两个话费送会员的服务,分别是会员随心享和会员 N 选 1 服务。先说不太划算的,其中会员 N 选 1 仅能选择爱奇艺、腾讯视频、优酷、芒果几个平台的视频会员,B 站以及更宽泛的音视频会员并不在内,流量也只是针对领取视频会员的定向流量,等同于只是用话费订阅了会员,性价比不高。

相比之下,同等价格的 20 元的会员随心选(下图)可以享受更加丰富的权益,音视频会员的选择上更加丰富,如果不领视频会员,偶尔喝个咖啡、吃个麦当劳、打车、购物、甚至游戏充值都能用上。

会员随心享服务

我就想着如果能有两个会员随心选服务就好了,一个用来领取 B 站/爱艺奇等视频会员平台用,另一个领取一些实打实的优惠作为线下生活用。(假设当月并没有可看的剧集)

恰好年底天翼提醒我兑换即将过期积分的时候,稍作研究才发现原来还有一个非常实用的「随心用乐享优惠包」服务,不仅可以通过积分订阅(不想继续扣费就取消),还能直接领取 10 元*2 张的微信立减金/云闪付代金券使用(话费补贴打工人狂喜)。值得一提的是,平时不舍得开电视会员的话,过年回家临时用积分开个影视尊享 PLUS 也非常实用。当然也有其他值得兑换的服务,从天翼生活 App 的「积分商城-电信精选」进入查看即可。

实际订阅下来,发现这个优惠包还是比较实用的,去便利店买个水、喝杯蜜雪冰城等都能使用。除了赠送的流量权益外,还能 0 元吃块吮指原味鸡,2 元喝一杯锡兰红茶,属于是「双厨小喜」。大家年底有多余的积分不要让运营商自动清空,不如兑个优惠包用用。

江苏电力积分兑换

@Voyager_1:你交的电费其实也可以累积积分,并且积分可以按照一定比例抵扣电费,也是在小红书刷到了江苏国网的「冷门福利」。在微信公众号搜索国网江苏电力,注册好后可以看到当前的积分。不幸的是,即使已经交过电费多年,也只按照微信公众号国网账号的激活时间为准,也就是说激活好后积分通常为 0,后续正常根据电费缴纳积分。

图源:小红书

积分的获取方式比较简单,通过预交电费和代扣电费两种方式均可获得 1 比 1 的等额积分(即交 1 元电费获 1 积分),注意不要用积分规则图里提到的其他电子化渠道交费,这样积分只能获取交费额的一半(即第二张图里的规则 4)。积分的兑换比例为 200 比 1,假设用户累积了 4000 积分,最后可以获得 20 元的电费,这些电费预存到用户的账户中,当支付电费时会自动扣除。

有一说一,评论区也有用户提到,自己激活时提示不属于低压用户不支持激活,可能是由于家庭有充电桩之类的原因,可以自行搜索下能否申诉解决。

掌上生活惠生活

@Voyager_1:号外号外,信用卡不仅可以用来买苹果 24 期分期,日常生活中也能有不错的商户优惠。拿我手头的招商银行信用卡来说,不光 App 在各大银行应用里出色拔萃,日常餐饮能用到的优惠还是比较务实的。

在掌上生活惠生活打开饭票界面,进入招牌餐厅必享榜,可以看到 2025 年上榜的热门餐厅。我常吃的滨寿司、寿司郎、达美乐披萨、点都德、巴奴火锅、左庭右院、西塔老太太等都有代金券,基本覆盖了火锅、烧烤、披萨、寿司等日常饮食品类,各位可以去查看自己所在地的榜单,兴许可以找到还不错又有优惠的店铺。

偶尔不想瑞一瑞的时候,在「饭票-星巴克专区」可以免费升杯、领取满 50 减 6 的券等;如果你是积分达人,可以 799 积分兑换中杯手工特调饮品。值得一提的是,积分兑换不仅可以门店扫码,也可以直接啡快点单,特别适合社恐星人,另外推荐加 3 元换大杯,6 元换超大杯。

如果还有多的积分,在掌上生活「首页-影票」购买电影票也可以用来折抵现金,最低一档是 299 积分抵扣 6 元,其次是 599 积分抵扣 12 元,1699 积分抵扣 37.9 元(以购买《疯狂动物城》为例)。下次看电影舍不得上 IMAX,不妨用积分直接提升一波体验。

花瓣地图赚「花币」

@尚白:我要讲的是花瓣地图的「羊毛」:旅「图」随手拍,花币轻松来。「花币」对于今年暑假刚给老婆送了一部 Pura X 而上一部华为系手机还是荣耀 V20 的我,是一个很遥远的词汇了。但我依稀记得,当年在 618 花了 1599 买的荣耀 V20,通过华为音乐下软件抽奖赚花币、华为视频下软件抽奖赚花币等等,硬是续了 5 年的腾讯视频 VIP、5 年的芒果 TVVIP,连带着把华为云空间也续了 3、4 年,杂七杂八算起来,手机不花钱,还挣了钱。有此战绩在前,在看到活动页面的当时,我立马仔细阅读了花币赚取方式:

玩法一、玩法二很简单,打开花瓣地图,点击一个地点,上传该地点的图片即可。首图一张是 2 块,被人捷足先登了也没关系,一张图 1 块,最多可以算 5 块。看见第二行的「同一账户每连续 3 天添加首图(非首图)」没?是的,还有额外奖励,三天一个周期,一个月按 30 天算,10 个周期,最高就是 (10+5)×10=150 块!

于是乎,在这个金秋十月,我们家最常见的对话就是:「我出去转转,顺便挣个花币。」首先从自家小区开始。门厅、单元楼、一个都不放过。慢慢就「祸害」起了隔壁沿街商铺。

一开始纯纯是为了薅羊毛而出门,后面成了习惯,出门看到新鲜的地点,都要打开地图看看。有些酒店都自带几十张精修航拍美照,我恨恨地挣上 5 块了事;有些苍蝇馆子意外地不乏首图,我猜测老板是位华为用户,肥水不流外人田;有些商家,比如瑞幸只有商品页面,没有上传图片页面,我便合上手机,扼腕叹息。

当然,实在没有机会外出的日子,难道就这样轻易「断签」?不,绝不可以!该活动不定时的推送中,也有大概这样意思的话:旅途结束了?整理一下照片挣花币吧。它并不强求你每天都灿烂多彩,如果哪一天拍了特别多的照片一股脑上传,突破了获取花币的上限,铁亏,那么在空闲的日子另行上传也行。这意味着你可以去翻一翻那些你拍过、存过、渐渐遗忘却无比珍惜的回忆。

我翻到了姥爷的照片,在百米高的玻璃栈道上,他扶着栏杆一步一笑一回头的样子,真的好治愈;我翻到了朋友开的店,一家可爱的水果店,店名叫做「有你好果子吃」;我翻到了当时说着「下次还要来吃」,却完全记不起地址的饭馆;翻到了老家人人都登过却没有人记录的山……

无奖竞猜,但是这座小小的山如今在花瓣地图上有了位置

走出去转转,也常回头看看,这是我今年薅过的最值得的羊毛:1060 花币。


感谢以上作者的投递,也欢迎你在评论区分享你薅到的那些「互联网数字羊毛」。我们将在日后开展更多不同领域和话题的征稿活动,也许会有更多优质投稿能够解答你的问题。

题图来自 Unsplash 

    • 新增绘图功能(实验),暂时没保存配置入数据库
      多轮对话生图、改图
      支持拖拽上传图片、拖拽调整图片附件顺序,图片附件预览
      支持并发生成 1-4 张图片
      支持提示词翻译
      右侧生成结果区可以对图片预览、下载、删除,可以查看详细参数和提示词

    • fix: 筛选模型时,匹配不到不会直接消失了

    同时生成多张图

    3

    拖拽上传和拖拽排序,预览图片

    【YPrompt】新增大香蕉多轮对话生图改图,来体验一下5

    提示词翻译

    【YPrompt】新增大香蕉多轮对话生图改图,来体验一下3

    配置提供商和模型

    配置模型参数


    📌 转载信息
    原作者:
    fish2018
    转载时间:
    2025/12/31 12:44:56

    刚发现字节在海外偷偷上线了一个类似 manus 的网站 AnyGen:

    让它跑了个 manus 发展历程的任务,效果还不错,可以直接调用 nano banana pro。


    📌 转载信息
    原作者:
    AlexFung
    转载时间:
    2025/12/30 15:30:16

    根据今日GitHub监控数据,整理出以下13个与AI视频制作、小说创作及有声书生成高度相关的开源项目。今日重点发现包括功能强大的电子书转有声书工具ebook2audiobook,以及多款视频生成与语音克隆的新兴工具。

    1. 有声书制作与语音克隆

    • ebook2audiobook

      • 项目介绍:一款功能强大的电子书转有声书转换器,支持CPU和GPU加速。
      • 核心功能

        • 多引擎支持:集成XTTSv2、Bark、Vits等多种TTS引擎,支持超过1110种语言。
        • 智能处理:支持按章节分割电子书,保留元数据,支持自定义语音克隆。
        • 广泛兼容:支持.epub、.pdf、.mobi等多种输入格式及.m4b、.mp3等输出格式,提供Gradio Web界面和Docker部署。
      • 项目地址https://github.com/DrewThomasson/ebook2audiobook
    • Dia-TTS-Server

      • 项目介绍:Dia TTS模型的自托管服务器实现。
      • 核心功能

        • API兼容:提供兼容OpenAI格式的API端点,易于集成。
        • 高级特性:支持SafeTensors/BF16加速、语音克隆及多角色对话生成,配备用户友好的Web UI。
      • 项目地址https://github.com/Gmzxdotzz/Dia-TTS-Server
    • ComfyUI-VoxCPM

      • 项目介绍:专为ComfyUI设计的插件,用于生成高表现力的语音。
      • 核心功能

        • 零样本克隆:支持在ComfyUI工作流中实现逼真的零样本语音克隆。
        • 情感表达:能够将文本转换为具有丰富情感色彩的音频。
      • 项目地址https://github.com/krishnasaivamsi/ComfyUI-VoxCPM
    • OpenVoice (VoltsyGM Fork)

      • 项目介绍:基于MIT和MyShell技术的即时语音克隆应用。
      • 核心功能

        • 风格控制:支持在克隆语音时精确控制说话的风格和语调。
      • 项目地址https://github.com/VoltsyGM/OpenVoice
    • local-voice-cloning-app

      • 项目介绍:一个轻量级的Python应用程序,用于本地语音克隆。
      • 核心功能

        • 简易工作流:提供简单的界面和流程来合成和克隆语音。
      • 项目地址https://github.com/Mohamedfat7i/local-voice-cloning-app

    2. 视频创作与生成

    • MOBIUS

      • 项目介绍:一个专门用于生成桌游教程视频的AI工具。
      • 核心功能

        • 垂直领域生成:专注于将规则文本转化为直观的教学视频内容。
      • 项目地址https://github.com/w9bikze8u4cbupc/MOBIUS
    • AI-course-generator

      • 项目介绍:利用AI将长视频讲座转化为结构化在线课程的工具。
      • 核心功能

        • 课程结构化:自动生成成绩单、模块划分、课程内容及测验题。集成OpenAI Whisper和GPT-4 Vision技术。
      • 项目地址https://github.com/DavidFW27/AI-course-generator
    • VibeArt

      • 项目介绍:一体化的图像与视频生成工具。
      • 核心功能

        • 模型集成:结合开源与闭源模型,利用社区训练的LoRA优化特定风格的生成效果,降低提示词门槛。
      • 项目地址https://github.com/vibeart-in/VibeArt
    • mulmocast-cli

      • 项目介绍:AI驱动的播客与视频生成器。
      • 核心功能

        • 脚本驱动:使用"MulmoScript"脚本语言生成多模态演示内容,集成OpenAI、Google、Anthropic等多家模型。
      • 项目地址https://github.com/receptron/mulmocast-cli
    • Hollywood-Quality-UGC-Ad-Generator

      • 项目介绍:利用单张产品照片生成好莱坞级视频广告的工具。
      • 核心功能

        • 多模型协作:通过n8n编排,结合Sora 2、GPT-4o和Gemini 2.5 Pro实现高质量广告生成。
      • 项目地址https://github.com/Saurabh22111998/Hollywood-Quality-UGC-Ad-Generator
    • AIQuoteClipGenerator

      • 项目介绍:基于MCP的自动化名言视频生成器,面向Instagram/TikTok。
      • 核心功能

        • 自动剪辑:自动生成包含名言的短视频片段,适合社交媒体快速传播。
      • 项目地址https://github.com/mercyg/AIQuoteClipGenerator

    3. 小说与故事创作

    • Ghost-Writer

      • 项目介绍:一个AI驱动的故事创作引擎。
      • 核心功能

        • 引导式写作:逐步引导用户完成小说创作过程,充当智能写作助手。
      • 项目地址https://github.com/MAS-D-KING/Ghost-Writer

    https://track.linso.ai/zh/execution/cmihfy83n07utl6945ke9i2yh

    即梦视频去水印下载 1
    即梦视频去水印下载 2
    图片&视频无水印下载

    // ==UserScript==
    // @name         即梦AI去水印
    // @namespace    http://tampermonkey.net/
    // @version      1.1.0
    // @description  通过重写XMLHttpRequest实现即梦AI 图片&视频下载去水印!
    // @author       mihuc
    // @match        https://jimeng.jianying.com/ai-tool/*
    // @icon         https://www.google.com/s2/favicons?sz=64&domain=jimeng.jianying.com
    // @grant        GM_xmlhttpRequest
    // @connect      *
    // ==/UserScript==
    
    (function () {
        'use strict';
        // 新增:有限大小的映射表与工具函数,用于保存 history id -> 对应 data
        const jimengDataMap = new Map(); // key: history id (uuid string), value: data object
        const JIMENG_DATA_MAP_MAX = 500;
    
        // 将数据写入 map(带容量控制)
        function setJimengDataMap(key, value) {
            if (!key || typeof key !== 'string' || value === undefined || value === null) return;
            try {
                jimengDataMap.set(key, value);
                // 简单淘汰最旧条目
                if (jimengDataMap.size > JIMENG_DATA_MAP_MAX) {
                    const oldestKey = jimengDataMap.keys().next().value;
                    if (oldestKey !== undefined) jimengDataMap.delete(oldestKey);
                }
            } catch (e) {
                console.warn('jimeng: setJimengDataMap error', e);
            }
        }
    
        // 从 map 读取数据
        function getJimengData(key) {
            if (!key) return null;
            return jimengDataMap.has(key) ? jimengDataMap.get(key) : null;
        }
    
        // 清空缓存(可选)
        function clearJimengDataMap() {
            try { jimengDataMap.clear(); } catch (e) { console.warn('jimeng: clearJimengDataMap error', e); }
        }
    
        /**
         * 尝试从响应中记录 get_history_by_ids 或 get_asset_list 类型的数据
         * @param {object} json - 已解析的 JSON 响应
         * @param {string} url - 请求 URL(可选,用于基于 URL 的判断)
         */
        function tryRecordHistoryFromResponse(json, url) {
            try {
                if (!json || typeof json !== 'object') return;
                const data = json.data;
                if (!data || typeof data !== 'object') return;
    
                // 通过 URL 判断接口类型
                const isHistoryEndpoint = typeof url === 'string' && url.indexOf('get_history_by_ids') !== -1;
                const isAssetEndpoint = typeof url === 'string' && url.indexOf('get_asset_list') !== -1;
    
                // 简单 UUID-like 正则匹配
                const uuidLike = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
    
                // 1) 处理 get_history_by_ids 风格的响应(已有逻辑)
                if (isHistoryEndpoint) {
                    for (const k in data) {
                        if (!Object.prototype.hasOwnProperty.call(data, k)) continue;
                        setJimengDataMap(k, data[k]);
                        // console.info('jimeng: recorded history key (by url)=', k);
    
                        if (data[k].item_list) {
                            for (const item of data[k].item_list) {
                                if (item.image && item.image.large_images) {
                                    const image_item = item.image.large_images[0];
                                    image_item["_type"] = "img"; // 标记类型,便于后续识别
                                    setJimengDataMap(image_item.image_uri, image_item);
    
                                }
                            }
                        }
                    }
                }
    
                // 2) 处理 get_asset_list 风格的响应:查找 data.asset_list 中的 submit_id(与 item_list 同级)
                if (isAssetEndpoint || Array.isArray(data.asset_list)) {
                    const list = Array.isArray(data.asset_list) ? data.asset_list : [];
                    for (const entry of list) {
                        // entry 可能是 { video: { submit_id, item_list: [...] , ... } } 或其他嵌套形式
                        if (!entry || typeof entry !== 'object') continue;
    
                        // 尝试常见路径:entry.video.submit_id 或 entry.submit_id
                        const candidates = [];
                        if (entry.video && typeof entry.video === 'object') candidates.push({ obj: entry.video, type: "video" });
                        if (entry.submit_id) candidates.push({ obj: entry, type: "video" });
    
                        if (entry.agent_conversation_session && entry.agent_conversation_session.submit_id_data_map) {
                            for (const key in entry.agent_conversation_session.submit_id_data_map) {
                                if (!Object.prototype.hasOwnProperty.call(entry.agent_conversation_session.submit_id_data_map, key)) continue;
                                const v = entry.agent_conversation_session.submit_id_data_map[key];
                                if (v.item_list) {
                                    const image_item = v.item_list[0].image.large_images[0];
                                    candidates.push({ obj: image_item, type: "img" });
                                }
                            }
                        }
                        // 也尝试向下查找一层含 submit_id 的对象(防止不同嵌套)
                        for (const key in entry) {
                            if (!Object.prototype.hasOwnProperty.call(entry, key)) continue;
                            const v = entry[key];
                            if (v && typeof v === 'object' && v.submit_id) {
                                candidates.push({ obj: v, type: "video" });
                            }
                        }
    
                        for (const c of candidates) {
                            const obj = c.obj;
                            obj["_type"] = c.type; // 标记类型,便于后续识别
                            const submitId = obj && obj.submit_id;
                            if (submitId && typeof submitId === 'string') {
                                // 将 submit_id 对应的整个对象记录(通常包含 item_list)
                                setJimengDataMap(submitId, obj);
                                console.info('jimeng: recorded asset submit_id=', submitId);
                            }
    
                            const imageUri = obj && obj.image_uri;
                            if (imageUri && typeof imageUri === 'string') {
                                setJimengDataMap(imageUri, obj);
                                console.info('jimeng: recorded asset image_uri=', imageUri);
                            }
                        }
                    }
                }
    
                // 3) 兜底:若不是明确的接口,也检测顶级 uuid-like key(旧逻辑)
                for (const k in data) {
                    if (!Object.prototype.hasOwnProperty.call(data, k)) continue;
                    const val = data[k];
                    if (uuidLike.test(k) && val && (val.item_list || val.video || Array.isArray(val.item_list))) {
                        setJimengDataMap(k, val);
                        console.info('jimeng: recorded history key (by content)=', k);
                    }
                }
            } catch (e) {
                console.warn('jimeng: tryRecordHistoryFromResponse error', e);
            }
        }
    
        // 暴露查询接口到 window,便于控制台快速查看(只读查询)
        try {
            Object.defineProperty(window, 'getJimengData', {
                value: function (id) { return getJimengData(id); },
                writable: false,
                configurable: true
            });
            // 仅供调试:暴露底层 Map(请勿在生产逻辑中修改)
            Object.defineProperty(window, '_jimengDataMap', {
                value: jimengDataMap,
                writable: false,
                configurable: true
            });
        } catch (e) {
            // 忽略在严格 CSP/沙箱环境下的定义失败
        }
    
        function decodeBase64Safe(b64) {
            if (!b64 || typeof b64 !== 'string') return null;
            // 过滤掉明显不是 base64 的短串
            if (b64.length < 16) return null;
            try {
                return atob(b64);
            } catch (e) {
                // 尝试 URL-safe 变体
                try {
                    const normalized = b64.replace(/-/g, '+').replace(/_/g, '/');
                    return atob(normalized);
                } catch (e2) {
                    return null;
                }
            }
        }
        // 从已缓存的响应数据(jimengDataMap)或响应对象中提取 main_url(优先返回第一个可解码的 URL)
        function extractMainUrlFromData(obj) {
            if (!obj || typeof obj !== 'object') return null;
            const seen = new Set();
            const type = obj._type || null;
            function walk(o) {
                if (!o || typeof o !== 'object') return null;
                if (seen.has(o)) return null;
                seen.add(o);
    
                for (const k in o) {
                    if (!Object.prototype.hasOwnProperty.call(o, k)) continue;
                    const v = o[k];
    
                    try {
                        // 发现 main_url 字段(通常为 base64),尝试解码并返回第一个有效 URL
                        if ((k === 'main_url' || k === 'mainUrl') && typeof v === 'string') {
                            const decoded = decodeBase64Safe(v);
                            if (decoded && decoded.startsWith('http')) return decoded;
                        }
    
                        // 有些视频信息以 video_list.video_1.main_url 存在
                        if (k === 'video_list' && typeof v === 'object') {
                            // 遍历 video_list 下的各质量项
                            for (const q in v) {
                                if (!Object.prototype.hasOwnProperty.call(v, q)) continue;
                                const item = v[q];
                                if (item && typeof item === 'object' && item.main_url) {
                                    const dec = decodeBase64Safe(item.main_url);
                                    if (dec && dec.startsWith('http')) return dec;
                                }
                            }
                        }
                        if (k === 'image_url' && typeof v === 'string' && type == "img") {
                            if (v) return v;
                        }
    
                        // 若字段为字符串化 JSON,尝试解析并继续查找
                        if (typeof v === 'string') {
                            try {
                                const parsed = JSON.parse(v);
                                const r = walk(parsed);
                                if (r) return r;
                            } catch (e) {
                                // ignore
                            }
                        }
    
                        // 递归对象或数组
                        if (typeof v === 'object') {
                            const r = walk(v);
                            if (r) return r;
                        }
                    } catch (e) {
                        // ignore individual errors
                    }
                }
                return null;
            }
    
            return walk(obj);
        }
    
        // 重写 XMLHttpRequest.prototype 以拦截响应文本
    
        function interceptXHR() {
            try {
                if (!window || !window.XMLHttpRequest) return;
                const XProto = window.XMLHttpRequest && window.XMLHttpRequest.prototype;
                if (!XProto) return;
                // 防止重复打补丁
                if (XProto.__jimeng_patched) return;
    
                const _open = XProto.open;
                const _send = XProto.send;
    
                XProto.open = function (method, url, ...rest) {
                    try {
                        this.__jimeng_url = url;
                    } catch (e) { /* ignore */ }
                    return _open.apply(this, [method, url, ...rest]);
                };
    
                XProto.send = function (body) {
                    try {
                        // attach listener safely
                        this.addEventListener && this.addEventListener('readystatechange', function () {
                            try {
                                if (this.readyState === 4) {
                                    // 仅在特定接口上处理,避免影响其它请求
                                    const reqUrl = (this.__jimeng_url || '').toString();
                                    if (!(reqUrl.indexOf('get_asset_list') !== -1 || reqUrl.indexOf('get_history_by_ids') !== -1)) {
                                        return; // 非目标接口,直接忽略
                                    }
    
                                    const txt = this.responseText;
                                    if (typeof txt === 'string' && txt.length > 100) {
                                        // 尝试直接解析为 JSON
                                        try {
                                            const parsed = JSON.parse(txt);
                                            // 新增:记录 get_history_by_ids 返回的顶级 key -> data
                                            tryRecordHistoryFromResponse(parsed, this.__jimeng_url);
                                        } catch (e) {
                                            // 回退:查找第一个 '{' 子串并尝试解析
                                            try {
                                                const idx = txt.indexOf('{');
                                                if (idx >= 0) {
                                                    const sub = txt.slice(idx);
                                                    const parsed2 = JSON.parse(sub);
                                                    // 新增回退解析时也尝试记录
                                                    tryRecordHistoryFromResponse(parsed2, this.__jimeng_url);
                                                }
                                            } catch (e2) {
                                                // 忽略不可解析的文本
                                            }
                                        }
                                    }
                                }
                            } catch (e) {
                                // 忽略单次处理错误,避免影响页面
                            }
                        });
                    } catch (e) {
                        // 忽略 attach 错误
                    }
                    return _send.apply(this, arguments);
                };
    
                // 标记已打补丁
                try { XProto.__jimeng_patched = true; } catch (e) { }
                console.info('jimeng: XHR interceptor installed');
            } catch (e) {
                console.warn('jimeng: interceptXHR failed', e);
            }
        }
    
        // 替换原先注入/监听调用:直接安装 XHR 拦截器(同时保留 fetch 拦截作为回退)
        try {
            interceptXHR();
        } catch (e) {
            console.warn('jimeng: failed to install XHR interceptor', e);
        }
    
        // 优先使用 GM_xmlhttpRequest 绕过页面 CSP,回退到 fetch
        function fetchBypassCSP(url, options = {}) {
            // options: { method, headers, responseType, onProgress } - responseType支持 'arraybuffer' 或 'blob' 等
            const method = options.method || 'GET';
            const headers = options.headers || {};
            const responseType = options.responseType || 'arraybuffer';
            const onProgress = options.onProgress; // 进度回调函数
    
            // 如果 Tampermonkey 提供 GM_xmlhttpRequest,则使用它(可绕过页面 CSP)
            if (typeof GM_xmlhttpRequest === 'function') {
                return new Promise((resolve, reject) => {
                    try {
                        GM_xmlhttpRequest({
                            method: method,
                            url: url,
                            headers: headers,
                            responseType: responseType,
                            onprogress(progressEvent) {
                                // 调用进度回调
                                if (typeof onProgress === 'function') {
                                    onProgress(progressEvent);
                                }
                            },
                            onload(res) {
                                // res.response 在 responseType=arraybuffer 时是 ArrayBuffer
                                resolve({
                                    ok: (res.status >= 200 && res.status < 300),
                                    status: res.status,
                                    statusText: res.statusText,
                                    response: res.response,
                                    responseHeaders: res.responseHeaders
                                });
                            },
                            onerror(err) {
                                reject(err);
                            },
                            ontimeout() {
                                reject(new Error('timeout'));
                            }
                        });
                    } catch (e) {
                        reject(e);
                    }
                });
            }
    
            // 回退:普通 fetch(受 CSP 限制,但无法支持进度监控)
            return (async () => {
                const resp = await fetch(url, { method, headers, mode: options.mode || 'cors' });
                const blob = await resp.blob();
                const arrayBuffer = await blob.arrayBuffer();
                return {
                    ok: resp.ok,
                    status: resp.status,
                    statusText: resp.statusText,
                    response: arrayBuffer
                };
            })();
        }
    
        /**
         * 进度弹窗管理器 - 管理多个下载弹窗的位置和堆叠
         */
        const ToastManager = {
            toasts: [], // 存储所有活跃的toast
            baseTop: 20, // 基础顶部距离
            spacing: 10, // toast之间的间距
    
            /**
             * 添加新的toast到管理器
             * @param {Object} toast - toast对象
             */
            add(toast) {
                this.toasts.push(toast);
                this.updatePositions();
            },
    
            /**
             * 从管理器中移除toast
             * @param {Object} toast - toast对象
             */
            remove(toast) {
                const index = this.toasts.indexOf(toast);
                if (index > -1) {
                    this.toasts.splice(index, 1);
                    this.updatePositions();
                }
            },
    
            /**
             * 更新所有toast的位置
             */
            updatePositions() {
                let currentTop = this.baseTop;
                this.toasts.forEach(toast => {
                    if (toast.container && toast.container.parentNode) {
                        toast.container.style.top = currentTop + 'px';
                        // 获取toast的实际高度
                        const height = toast.container.offsetHeight;
                        currentTop += height + this.spacing;
                    }
                });
            }
        };
    
        /**
         * 创建右上角进度弹窗
         * @returns {Object} 包含容器元素和更新方法的对象
         */
        function createProgressToast(msg = "正在下载视频...") {
            const container = document.createElement('div');
            container.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                min-width: 300px;
                max-width: 400px;
                background: rgba(0, 0, 0, 0.9);
                color: white;
                padding: 16px 20px;
                border-radius: 8px;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
                z-index: 99999;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
                font-size: 14px;
                line-height: 1.5;
                transition: top 0.3s ease, opacity 0.3s ease;
            `;
    
            const title = document.createElement('div');
            title.style.cssText = `
                font-weight: 600;
                margin-bottom: 8px;
                font-size: 15px;
            `;
            title.textContent = msg;
    
            const progressBarBg = document.createElement('div');
            progressBarBg.style.cssText = `
                width: 100%;
                height: 4px;
                background: rgba(255, 255, 255, 0.2);
                border-radius: 2px;
                margin: 8px 0;
                overflow: hidden;
            `;
    
            const progressBar = document.createElement('div');
            progressBar.style.cssText = `
                width: 0%;
                height: 100%;
                background: linear-gradient(90deg, #4CAF50, #8BC34A);
                border-radius: 2px;
                transition: width 0.3s ease;
            `;
            progressBarBg.appendChild(progressBar);
    
            const statusText = document.createElement('div');
            statusText.style.cssText = `
                font-size: 12px;
                color: rgba(255, 255, 255, 0.8);
                margin-top: 8px;
            `;
            statusText.textContent = '准备下载...';
    
            container.appendChild(title);
            container.appendChild(progressBarBg);
            container.appendChild(statusText);
            document.body.appendChild(container);
    
            const toast = {
                container,
                title,
                progressBar,
                statusText,
                /**
                 * 更新进度
                 * @param {number} percent - 进度百分比 (0-100)
                 * @param {string} status - 状态文本
                 */
                update(percent, status) {
                    progressBar.style.width = percent + '%';
                    if (status) statusText.textContent = status;
                },
                /**
                 * 设置为成功状态
                 * @param {string} message - 成功消息
                 */
                success(message) {
                    title.textContent = '✓ 下载完成';
                    progressBar.style.background = 'linear-gradient(90deg, #4CAF50, #66BB6A)';
                    statusText.textContent = message || '视频已保存';
                },
                /**
                 * 设置为错误状态
                 * @param {string} message - 错误消息
                 */
                error(message) {
                    title.textContent = '✗ 下载失败';
                    progressBar.style.background = 'linear-gradient(90deg, #f44336, #e57373)';
                    statusText.textContent = message || '请重试';
                },
                /**
                 * 移除弹窗
                 * @param {number} delay - 延迟时间(毫秒)
                 */
                remove(delay = 0) {
                    setTimeout(() => {
                        container.style.opacity = '0';
                        setTimeout(() => {
                            if (container.parentNode) {
                                container.parentNode.removeChild(container);
                            }
                            // 从管理器中移除
                            ToastManager.remove(toast);
                        }, 300);
                    }, delay);
                }
            };
    
            // 添加到管理器
            ToastManager.add(toast);
    
            return toast;
        }
    
        /**
         * 下载视频通用函数(带进度显示)
         * @param {string} url - 视频URL
         * @param {string} filename - 可选的文件名
         */
        async function downloadVideo(url, filename) {
            const toast = createProgressToast();
    
            try {
                const res = await fetchBypassCSP(url, {
                    responseType: 'arraybuffer',
                    method: 'GET',
                    onProgress: (event) => {
                        if (event.lengthComputable) {
                            const percent = Math.round((event.loaded / event.total) * 100);
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            const totalMB = (event.total / 1024 / 1024).toFixed(2);
                            toast.update(percent, `${loadedMB} MB / ${totalMB} MB (${percent}%)`);
                        } else {
                            // 无法获取总大小时显示已下载量
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            toast.update(50, `已下载 ${loadedMB} MB...`);
                        }
                    }
                });
    
                if (!res || !res.ok) throw new Error('请求失败,status=' + (res && res.status));
    
                toast.update(100, '处理文件中...');
    
                const arrayBuffer = res.response;
                const blob = new Blob([arrayBuffer], { type: 'video/mp4' });
                const objectUrl = URL.createObjectURL(blob);
    
                const link = document.createElement('a');
                const now = new Date();
                const dateStr = now.toISOString()
                    .slice(0, 19)
                    .replace('T', '_')
                    .replace(/:/g, '-');
                link.download = filename || `RWater_${dateStr}.mp4`;
                link.href = objectUrl;
                link.target = '_blank';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
    
                URL.revokeObjectURL(objectUrl);
    
                toast.success('视频已开始下载');
                toast.remove(1000);
            } catch (e) {
                console.error('下载失败:', e);
                toast.error(e.message || '下载失败,请重试');
                toast.remove(2000);
            }
        }
    
        async function downloadImage(url, filename) {
            const toast = createProgressToast("正在下载图片...");
    
            try {
                const res = await fetchBypassCSP(url, {
                    responseType: 'arraybuffer',
                    method: 'GET',
                    onProgress: (event) => {
                        if (event.lengthComputable) {
                            const percent = Math.round((event.loaded / event.total) * 100);
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            const totalMB = (event.total / 1024 / 1024).toFixed(2);
                            toast.update(percent, `${loadedMB} MB / ${totalMB} MB (${percent}%)`);
                        } else {
                            // 无法获取总大小时显示已下载量
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            toast.update(50, `已下载 ${loadedMB} MB...`);
                        }
                    }
                });
    
                if (!res || !res.ok) throw new Error('请求失败,status=' + (res && res.status));
    
                toast.update(100, '处理文件中...');
    
                const arrayBuffer = res.response;
                const blob = new Blob([arrayBuffer], { type: 'image/png' });
                const objectUrl = URL.createObjectURL(blob);
    
                const link = document.createElement('a');
                const now = new Date();
                const dateStr = now.toISOString()
                    .slice(0, 19)
                    .replace('T', '_')
                    .replace(/:/g, '-');
                link.download = filename || `RWater_${dateStr}.png`;
                link.href = objectUrl;
                link.target = '_blank';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
    
                URL.revokeObjectURL(objectUrl);
    
                toast.success('图片已开始下载');
                toast.remove(1000);
            } catch (e) {
                console.error('下载失败:', e);
                toast.error(e.message || '下载失败,请重试');
                toast.remove(2000);
            }
        }
        /**
         * 初始化即梦网站的功能
         */
        function initJimengSite() {
            const observer = new MutationObserver(() => {
                jimeng_addVideoDownloadButton();
                jimeng_addImageDownloadButton();
            });
    
            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['style', 'class']
            });
    
            // Also add event listeners for mouse interactions that might trigger UI changes
            document.addEventListener('mouseover', () => {
                setTimeout(() => {
                    jimeng_addVideoDownloadButton();
                    jimeng_addImageDownloadButton();
                }, 100);
            }, true);
    
            console.log('即梦: 初始化无水印下载工具');
            jimeng_addVideoDownloadButton();
            jimeng_addImageDownloadButton();
        }
    
        /**
         * 创建即梦视频下载按钮
         * @returns {HTMLElement} 下载按钮元素
         */
        function jimeng_createVideoDownloadButton() {
            const button = document.createElement('div');
            button.className = 'lv-btn lv-btn-secondary lv-btn-size-default lv-btn-shape-square baseButton-LQGhrC download-btn';
            const div = document.createElement('div');
            div.textContent = '无水印下载';
            button.appendChild(div);
    
            button.title = '无水印下载';
            button.style = '--right-padding: 14px; align-items: center;background-color: var(--bg-block-primary-default); border-radius: 8px; color: var(--text-primary, #f5fbff); display: flex; font-family: PingFang SC;font-size: 12px; font-weight: 400; gap: 4px; justify-content: center; line-height: 20px; padding: 8px var(--right-padding) 8px 12px; position: relative;'
            return button;
        }
        function jimeng_createImageDownloadButton() {
            const button = document.createElement('span');
            button.className = 'download-btn';
            button.textContent = "无水印下载";
            button.style = 'display: block;font-size: 12px;position: absolute;top: 5px;left: 5px;background: rgba(255, 255, 255, 0.87);border-radius: 5px;padding: 3px 10px;z-index: 100;'
            return button;
        }
    
        function jimeng_getVideoDataId(downloadBtn) {
            console.log('即梦: 开始查找视频元素...');
            const parentItem = downloadBtn.closest('[class*="item-"]');
            return parentItem ? parentItem.getAttribute('data-id') : null;
        }
        /**
         * 获取即梦视频URL
         * @param {Element} downloadBtn - 下载按钮元素
         * @returns {string|null} 视频URL或null
         */
        function jimeng_getVideoUrl(downloadBtn) {
            console.log('即梦: 开始查找视频元素...');
            const parentItem = downloadBtn.closest('[class*="item-"]');
    
            const videoWrapper = parentItem.querySelector('div[class^="video-node-wrapper-"]');
            if (!videoWrapper) {
                alert('未找到视频');
                console.log('即梦: 未找到videoWrapper');
                return null;
            }
    
            let videoElement = videoWrapper.querySelector('video');
            if (!videoElement) {
                alert('未找到视频');
                console.log('即梦: 未找到video元素');
                return null;
            }
    
            if (videoElement && videoElement.src) {
                console.log('即梦: 找到视频元素:', {
                    src: videoElement.src,
                    className: videoElement.className,
                    width: videoElement.width,
                    height: videoElement.height,
                    naturalWidth: videoElement.naturalWidth,
                    naturalHeight: videoElement.naturalHeight,
                    attributes: Array.from(videoElement.attributes).map(attr => `${attr.name}="${attr.value}"`).join(', ')
                });
                return videoElement.src;
            }
    
            alert('未找到视频');
            console.log('即梦: 未找到合适的视频');
            return null;
        }
        function jimeng_getImageUrl(downloadBtn) {
            console.log('即梦: 开始查找图片元素...');
            const parentItem = downloadBtn.parentNode;
    
            const imageElement = parentItem.querySelector('img[class^="image-"]');
            if (!imageElement) {
                alert('未找到图片');
                console.log('即梦: 未找到imageElement');
                return null;
            }
            if (imageElement && imageElement.src) {
                console.log('即梦: 找到图片元素:', {
                    src: imageElement.src,
                });
                return imageElement.src;
            }
    
            alert('未找到图片');
            console.log('即梦: 未找到合适的图片');
            return null;
        }
        /**
         * 添加视频下载按钮到即梦页面
         */
        function jimeng_addVideoDownloadButton() {
            const videoContents = document.querySelectorAll('div[class^="video-record-"]');
            if (!videoContents || videoContents.length === 0) {
                return;
            }
            for (let i = 0; i < videoContents.length; i++) {
                const topActionBar = videoContents[i].querySelector('div[class^="record-bottom-slots-"]');
                if (!topActionBar) {
                    continue;
                }
                if (topActionBar.querySelector('div[class^="image-record-content-"]')) {
                    continue;
                }
                if (topActionBar.querySelector('.download-btn')) {
                    continue;
                }
                jimeng_processSingleVideoButton(topActionBar);
            }
        }
    
        /**
         * 添加图片下载按钮到即梦页面
         */
        function jimeng_addImageDownloadButton() {
            const imgContents = document.querySelectorAll('div[class^="agentic-image-record-item-"]');
            if (!imgContents || imgContents.length === 0) {
                return;
            }
            for (let i = 0; i < imgContents.length; i++) {
                const topActionBar = imgContents[i].querySelector('div[class^="image-card-container-"]');
                if (!topActionBar) {
                    continue;
                }
    
                if (topActionBar.querySelector('.download-btn')) {
                    continue;
                }
                jimeng_processSingleImageButton(topActionBar);
            }
        }
    
        /**
         * 处理单个视频按钮(已简化:不再依赖 jimengVideoMap)
         * @param {Element} topActionBar - 操作栏元素
         */
        function jimeng_processSingleVideoButton(topActionBar) {
            const downloadBtn = jimeng_createVideoDownloadButton();
            topActionBar.insertBefore(downloadBtn, topActionBar.firstChild);
            console.info('即梦: 添加视频下载按钮');
    
            downloadBtn.addEventListener('click', async () => {
                console.log('即梦: 点击视频下载按钮');
                const videoDataId = jimeng_getVideoDataId(downloadBtn);
                const videoUrl = jimeng_getVideoUrl(downloadBtn);
                console.log('即梦: 获取到的视频URL:', videoUrl);
                let finalUrl = videoUrl;
    
                try {
                    // 2) 若仍然没有 finalUrl,尝试用 videoDataId 从 jimengDataMap 中查找 main_url
                    if (videoDataId) {
                        const cached = getJimengData(videoDataId);
                        if (cached) {
                            const extracted = extractMainUrlFromData(cached);
                            if (extracted) {
                                finalUrl = extracted;
                                console.log('即梦: 从 jimengDataMap 提取到 main_url,使用该 URL 下载', finalUrl);
                            }
                        }
                    }
    
                    if (!finalUrl) {
                        alert('未找到可下载的视频链接');
                        console.error('即梦: 未能解析出有效的下载 URL');
                        return;
                    }
    
                    downloadBtn.style.opacity = '0.5';
                    downloadBtn.style.pointerEvents = 'none';
                    await downloadVideo(finalUrl);
                } catch (e) {
                    console.error('即梦: 下载过程中出错', e);
                    alert('下载失败,请重试(查看控制台以获得更多信息)');
                } finally {
                    downloadBtn.style.opacity = '1';
                    downloadBtn.style.pointerEvents = 'auto';
                }
            });
        }
        function extractTosPath(url) {
            // 方法1: 使用正则表达式
            const match = url.match(/tos-[^/]+\/[a-f0-9]+/);
            return match ? match[0] : null;
        }
        function jimeng_processSingleImageButton(topActionBar) {
            const downloadBtn = jimeng_createImageDownloadButton();
            topActionBar.insertBefore(downloadBtn, topActionBar.firstChild);
            console.info('即梦: 添加图片下载按钮');
    
            downloadBtn.addEventListener('click', async () => {
                console.log('即梦: 点击图片下载按钮');
                const imageUrl = jimeng_getImageUrl(downloadBtn);
                console.log('即梦: 获取到的图片URL:', imageUrl);
                if (!imageUrl) {
                    alert('未找到可下载的图片链接');
                    return;
                }
                let finalUrl = imageUrl;
    
                try {
                    // 使用正则和分段处理规范化 imageUri:去除域名、query、尺寸、变体(~...)与扩展名,优先返回 "xxx/yyy" 或单段 id
                    let imageUri = extractTosPath(imageUrl);
                    // 2) 若仍然没有 finalUrl,尝试用 videoDataId 从 jimengDataMap 中查找 main_url
                    if (imageUri) {
                        const cached = getJimengData(imageUri);
                        if (cached) {
                            const extracted = extractMainUrlFromData(cached);
                            if (extracted) {
                                finalUrl = extracted;
                                console.log('即梦: 从 jimengDataMap 提取到image_url,使用该 URL 下载', finalUrl);
                            }
                        }
                    }
    
                    if (!finalUrl) {
                        alert('未找到可下载的图片链接');
                        console.error('即梦: 未能解析出有效的下载 URL');
                        return;
                    }
    
                    downloadBtn.style.opacity = '0.5';
                    downloadBtn.style.pointerEvents = 'none';
                    await downloadImage(finalUrl);
                } catch (e) {
                    console.error('即梦: 下载过程中出错', e);
                    alert('下载失败,请重试(查看控制台以获得更多信息)');
                } finally {
                    downloadBtn.style.opacity = '1';
                    downloadBtn.style.pointerEvents = 'auto';
                }
            });
        }
        initJimengSite();
    
    })();

    仅视频无水印下载

    // ==UserScript==
    // @name         即梦AI去水印
    // @namespace    http://tampermonkey.net/
    // @version      1.1.0
    // @description  通过重写XMLHttpRequest实现即梦AI视频下载去水印!
    // @author       mihuc
    // @match        https://jimeng.jianying.com/ai-tool/*
    // @icon         https://www.google.com/s2/favicons?sz=64&domain=jimeng.jianying.com
    // @grant        GM_xmlhttpRequest
    // @connect      *
    // ==/UserScript==
    
    (function () {
        'use strict';
        // 新增:有限大小的映射表与工具函数,用于保存 history id -> 对应 data
        const jimengDataMap = new Map(); // key: history id (uuid string), value: data object
        const JIMENG_DATA_MAP_MAX = 500;
    
        // 将数据写入 map(带容量控制)
        function setJimengDataMap(key, value) {
            if (!key || typeof key !== 'string' || value === undefined || value === null) return;
            try {
                jimengDataMap.set(key, value);
                // 简单淘汰最旧条目
                if (jimengDataMap.size > JIMENG_DATA_MAP_MAX) {
                    const oldestKey = jimengDataMap.keys().next().value;
                    if (oldestKey !== undefined) jimengDataMap.delete(oldestKey);
                }
            } catch (e) {
                console.warn('jimeng: setJimengDataMap error', e);
            }
        }
    
        // 从 map 读取数据
        function getJimengData(key) {
            if (!key) return null;
            return jimengDataMap.has(key) ? jimengDataMap.get(key) : null;
        }
    
        // 清空缓存(可选)
        function clearJimengDataMap() {
            try { jimengDataMap.clear(); } catch (e) { console.warn('jimeng: clearJimengDataMap error', e); }
        }
    
        /**
         * 尝试从响应中记录 get_history_by_ids 或 get_asset_list 类型的数据
         * @param {object} json - 已解析的 JSON 响应
         * @param {string} url - 请求 URL(可选,用于基于 URL 的判断)
         */
        function tryRecordHistoryFromResponse(json, url) {
            try {
                if (!json || typeof json !== 'object') return;
                const data = json.data;
                if (!data || typeof data !== 'object') return;
    
                // 通过 URL 判断接口类型
                const isHistoryEndpoint = typeof url === 'string' && url.indexOf('get_history_by_ids') !== -1;
                const isAssetEndpoint = typeof url === 'string' && url.indexOf('get_asset_list') !== -1;
    
                // 简单 UUID-like 正则匹配
                const uuidLike = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
    
                // 1) 处理 get_history_by_ids 风格的响应(已有逻辑)
                if (isHistoryEndpoint) {
                    for (const k in data) {
                        if (!Object.prototype.hasOwnProperty.call(data, k)) continue;
                        setJimengDataMap(k, data[k]);
                        console.info('jimeng: recorded history key (by url)=', k);
                    }
                }
    
                // 2) 处理 get_asset_list 风格的响应:查找 data.asset_list 中的 submit_id(与 item_list 同级)
                if (isAssetEndpoint || Array.isArray(data.asset_list)) {
                    const list = Array.isArray(data.asset_list) ? data.asset_list : [];
                    for (const entry of list) {
                        // entry 可能是 { video: { submit_id, item_list: [...] , ... } } 或其他嵌套形式
                        if (!entry || typeof entry !== 'object') continue;
    
                        // 尝试常见路径:entry.video.submit_id 或 entry.submit_id
                        const candidates = [];
    
                        if (entry.video && typeof entry.video === 'object') candidates.push({ obj: entry.video, parent: entry });
                        if (entry.submit_id) candidates.push({ obj: entry, parent: entry });
    
                        // 也尝试向下查找一层含 submit_id 的对象(防止不同嵌套)
                        for (const key in entry) {
                            if (!Object.prototype.hasOwnProperty.call(entry, key)) continue;
                            const v = entry[key];
                            if (v && typeof v === 'object' && v.submit_id) {
                                candidates.push({ obj: v, parent: entry });
                            }
                        }
    
                        for (const c of candidates) {
                            const obj = c.obj;
                            const submitId = obj && obj.submit_id;
                            if (submitId && typeof submitId === 'string') {
                                // 将 submit_id 对应的整个对象记录(通常包含 item_list)
                                setJimengDataMap(submitId, obj);
                                console.info('jimeng: recorded asset submit_id=', submitId);
                            }
                        }
                    }
                }
    
                // 3) 兜底:若不是明确的接口,也检测顶级 uuid-like key(旧逻辑)
                for (const k in data) {
                    if (!Object.prototype.hasOwnProperty.call(data, k)) continue;
                    const val = data[k];
                    if (uuidLike.test(k) && val && (val.item_list || val.video || Array.isArray(val.item_list))) {
                        setJimengDataMap(k, val);
                        console.info('jimeng: recorded history key (by content)=', k);
                    }
                }
            } catch (e) {
                console.warn('jimeng: tryRecordHistoryFromResponse error', e);
            }
        }
    
        // 暴露查询接口到 window,便于控制台快速查看(只读查询)
        try {
            Object.defineProperty(window, 'getJimengData', {
                value: function (id) { return getJimengData(id); },
                writable: false,
                configurable: true
            });
            // 仅供调试:暴露底层 Map(请勿在生产逻辑中修改)
            Object.defineProperty(window, '_jimengDataMap', {
                value: jimengDataMap,
                writable: false,
                configurable: true
            });
        } catch (e) {
            // 忽略在严格 CSP/沙箱环境下的定义失败
        }
    
        function getVideoUrlPrams(url) {
            const urlObj = new URL(url);
            const params = {};
            urlObj.searchParams.forEach((value, key) => {
                params[key] = value;
            });
            return params;
        }
    
    
    
        function decodeBase64Safe(b64) {
            if (!b64 || typeof b64 !== 'string') return null;
            // 过滤掉明显不是 base64 的短串
            if (b64.length < 16) return null;
            try {
                return atob(b64);
            } catch (e) {
                // 尝试 URL-safe 变体
                try {
                    const normalized = b64.replace(/-/g, '+').replace(/_/g, '/');
                    return atob(normalized);
                } catch (e2) {
                    return null;
                }
            }
        }
        // 从已缓存的响应数据(jimengDataMap)或响应对象中提取 main_url(优先返回第一个可解码的 URL)
        function extractMainUrlFromData(obj) {
            if (!obj || typeof obj !== 'object') return null;
            const seen = new Set();
    
            function walk(o) {
                if (!o || typeof o !== 'object') return null;
                if (seen.has(o)) return null;
                seen.add(o);
    
                for (const k in o) {
                    if (!Object.prototype.hasOwnProperty.call(o, k)) continue;
                    const v = o[k];
    
                    try {
                        // 发现 main_url 字段(通常为 base64),尝试解码并返回第一个有效 URL
                        if ((k === 'main_url' || k === 'mainUrl') && typeof v === 'string') {
                            const decoded = decodeBase64Safe(v);
                            if (decoded && decoded.startsWith('http')) return decoded;
                        }
    
                        // 有些视频信息以 video_list.video_1.main_url 存在
                        if (k === 'video_list' && typeof v === 'object') {
                            // 遍历 video_list 下的各质量项
                            for (const q in v) {
                                if (!Object.prototype.hasOwnProperty.call(v, q)) continue;
                                const item = v[q];
                                if (item && typeof item === 'object' && item.main_url) {
                                    const dec = decodeBase64Safe(item.main_url);
                                    if (dec && dec.startsWith('http')) return dec;
                                }
                            }
                        }
    
                        // 若字段为字符串化 JSON,尝试解析并继续查找
                        if (typeof v === 'string') {
                            try {
                                const parsed = JSON.parse(v);
                                const r = walk(parsed);
                                if (r) return r;
                            } catch (e) {
                                // ignore
                            }
                        }
    
                        // 递归对象或数组
                        if (typeof v === 'object') {
                            const r = walk(v);
                            if (r) return r;
                        }
                    } catch (e) {
                        // ignore individual errors
                    }
                }
                return null;
            }
    
            return walk(obj);
        }
    
        // 重写 XMLHttpRequest.prototype 以拦截响应文本
    
        function interceptXHR() {
            try {
                if (!window || !window.XMLHttpRequest) return;
                const XProto = window.XMLHttpRequest && window.XMLHttpRequest.prototype;
                if (!XProto) return;
                // 防止重复打补丁
                if (XProto.__jimeng_patched) return;
    
                const _open = XProto.open;
                const _send = XProto.send;
    
                XProto.open = function (method, url, ...rest) {
                    try {
                        this.__jimeng_url = url;
                    } catch (e) { /* ignore */ }
                    return _open.apply(this, [method, url, ...rest]);
                };
    
                XProto.send = function (body) {
                    try {
                        // attach listener safely
                        this.addEventListener && this.addEventListener('readystatechange', function () {
                            try {
                                if (this.readyState === 4) {
                                    // 仅在特定接口上处理,避免影响其它请求
                                    const reqUrl = (this.__jimeng_url || '').toString();
                                    if (!(reqUrl.indexOf('get_asset_list') !== -1 || reqUrl.indexOf('get_history_by_ids') !== -1)) {
                                        return; // 非目标接口,直接忽略
                                    }
    
                                    const txt = this.responseText;
                                    if (typeof txt === 'string' && txt.length > 100) {
                                        // 尝试直接解析为 JSON
                                        try {
                                            const parsed = JSON.parse(txt);
                                            // 新增:记录 get_history_by_ids 返回的顶级 key -> data
                                            tryRecordHistoryFromResponse(parsed, this.__jimeng_url);
                                        } catch (e) {
                                            // 回退:查找第一个 '{' 子串并尝试解析
                                            try {
                                                const idx = txt.indexOf('{');
                                                if (idx >= 0) {
                                                    const sub = txt.slice(idx);
                                                    const parsed2 = JSON.parse(sub);
                                                    // 新增回退解析时也尝试记录
                                                    tryRecordHistoryFromResponse(parsed2, this.__jimeng_url);
                                                }
                                            } catch (e2) {
                                                // 忽略不可解析的文本
                                            }
                                        }
                                    }
                                }
                            } catch (e) {
                                // 忽略单次处理错误,避免影响页面
                            }
                        });
                    } catch (e) {
                        // 忽略 attach 错误
                    }
                    return _send.apply(this, arguments);
                };
    
                // 标记已打补丁
                try { XProto.__jimeng_patched = true; } catch (e) { }
                console.info('jimeng: XHR interceptor installed');
            } catch (e) {
                console.warn('jimeng: interceptXHR failed', e);
            }
        }
    
        // 替换原先注入/监听调用:直接安装 XHR 拦截器(同时保留 fetch 拦截作为回退)
        try {
            interceptXHR();
        } catch (e) {
            console.warn('jimeng: failed to install XHR interceptor', e);
        }
    
        // 优先使用 GM_xmlhttpRequest 绕过页面 CSP,回退到 fetch
        function fetchBypassCSP(url, options = {}) {
            // options: { method, headers, responseType, onProgress } - responseType支持 'arraybuffer' 或 'blob' 等
            const method = options.method || 'GET';
            const headers = options.headers || {};
            const responseType = options.responseType || 'arraybuffer';
            const onProgress = options.onProgress; // 进度回调函数
    
            // 如果 Tampermonkey 提供 GM_xmlhttpRequest,则使用它(可绕过页面 CSP)
            if (typeof GM_xmlhttpRequest === 'function') {
                return new Promise((resolve, reject) => {
                    try {
                        GM_xmlhttpRequest({
                            method: method,
                            url: url,
                            headers: headers,
                            responseType: responseType,
                            onprogress(progressEvent) {
                                // 调用进度回调
                                if (typeof onProgress === 'function') {
                                    onProgress(progressEvent);
                                }
                            },
                            onload(res) {
                                // res.response 在 responseType=arraybuffer 时是 ArrayBuffer
                                resolve({
                                    ok: (res.status >= 200 && res.status < 300),
                                    status: res.status,
                                    statusText: res.statusText,
                                    response: res.response,
                                    responseHeaders: res.responseHeaders
                                });
                            },
                            onerror(err) {
                                reject(err);
                            },
                            ontimeout() {
                                reject(new Error('timeout'));
                            }
                        });
                    } catch (e) {
                        reject(e);
                    }
                });
            }
    
            // 回退:普通 fetch(受 CSP 限制,但无法支持进度监控)
            return (async () => {
                const resp = await fetch(url, { method, headers, mode: options.mode || 'cors' });
                const blob = await resp.blob();
                const arrayBuffer = await blob.arrayBuffer();
                return {
                    ok: resp.ok,
                    status: resp.status,
                    statusText: resp.statusText,
                    response: arrayBuffer
                };
            })();
        }
    
        /**
         * 进度弹窗管理器 - 管理多个下载弹窗的位置和堆叠
         */
        const ToastManager = {
            toasts: [], // 存储所有活跃的toast
            baseTop: 20, // 基础顶部距离
            spacing: 10, // toast之间的间距
            
            /**
             * 添加新的toast到管理器
             * @param {Object} toast - toast对象
             */
            add(toast) {
                this.toasts.push(toast);
                this.updatePositions();
            },
            
            /**
             * 从管理器中移除toast
             * @param {Object} toast - toast对象
             */
            remove(toast) {
                const index = this.toasts.indexOf(toast);
                if (index > -1) {
                    this.toasts.splice(index, 1);
                    this.updatePositions();
                }
            },
            
            /**
             * 更新所有toast的位置
             */
            updatePositions() {
                let currentTop = this.baseTop;
                this.toasts.forEach(toast => {
                    if (toast.container && toast.container.parentNode) {
                        toast.container.style.top = currentTop + 'px';
                        // 获取toast的实际高度
                        const height = toast.container.offsetHeight;
                        currentTop += height + this.spacing;
                    }
                });
            }
        };
    
        /**
         * 创建右上角进度弹窗
         * @returns {Object} 包含容器元素和更新方法的对象
         */
        function createProgressToast() {
            const container = document.createElement('div');
            container.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                min-width: 300px;
                max-width: 400px;
                background: rgba(0, 0, 0, 0.9);
                color: white;
                padding: 16px 20px;
                border-radius: 8px;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
                z-index: 99999;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
                font-size: 14px;
                line-height: 1.5;
                transition: top 0.3s ease, opacity 0.3s ease;
            `;
    
            const title = document.createElement('div');
            title.style.cssText = `
                font-weight: 600;
                margin-bottom: 8px;
                font-size: 15px;
            `;
            title.textContent = '正在下载视频...';
    
            const progressBarBg = document.createElement('div');
            progressBarBg.style.cssText = `
                width: 100%;
                height: 4px;
                background: rgba(255, 255, 255, 0.2);
                border-radius: 2px;
                margin: 8px 0;
                overflow: hidden;
            `;
    
            const progressBar = document.createElement('div');
            progressBar.style.cssText = `
                width: 0%;
                height: 100%;
                background: linear-gradient(90deg, #4CAF50, #8BC34A);
                border-radius: 2px;
                transition: width 0.3s ease;
            `;
            progressBarBg.appendChild(progressBar);
    
            const statusText = document.createElement('div');
            statusText.style.cssText = `
                font-size: 12px;
                color: rgba(255, 255, 255, 0.8);
                margin-top: 8px;
            `;
            statusText.textContent = '准备下载...';
    
            container.appendChild(title);
            container.appendChild(progressBarBg);
            container.appendChild(statusText);
            document.body.appendChild(container);
    
            const toast = {
                container,
                title,
                progressBar,
                statusText,
                /**
                 * 更新进度
                 * @param {number} percent - 进度百分比 (0-100)
                 * @param {string} status - 状态文本
                 */
                update(percent, status) {
                    progressBar.style.width = percent + '%';
                    if (status) statusText.textContent = status;
                },
                /**
                 * 设置为成功状态
                 * @param {string} message - 成功消息
                 */
                success(message) {
                    title.textContent = '✓ 下载完成';
                    progressBar.style.background = 'linear-gradient(90deg, #4CAF50, #66BB6A)';
                    statusText.textContent = message || '视频已保存';
                },
                /**
                 * 设置为错误状态
                 * @param {string} message - 错误消息
                 */
                error(message) {
                    title.textContent = '✗ 下载失败';
                    progressBar.style.background = 'linear-gradient(90deg, #f44336, #e57373)';
                    statusText.textContent = message || '请重试';
                },
                /**
                 * 移除弹窗
                 * @param {number} delay - 延迟时间(毫秒)
                 */
                remove(delay = 0) {
                    setTimeout(() => {
                        container.style.opacity = '0';
                        setTimeout(() => {
                            if (container.parentNode) {
                                container.parentNode.removeChild(container);
                            }
                            // 从管理器中移除
                            ToastManager.remove(toast);
                        }, 300);
                    }, delay);
                }
            };
    
            // 添加到管理器
            ToastManager.add(toast);
    
            return toast;
        }
    
        /**
         * 下载视频通用函数(带进度显示)
         * @param {string} url - 视频URL
         * @param {string} filename - 可选的文件名
         */
        async function downloadVideo(url, filename) {
            const toast = createProgressToast();
            
            try {
                const res = await fetchBypassCSP(url, { 
                    responseType: 'arraybuffer', 
                    method: 'GET',
                    onProgress: (event) => {
                        if (event.lengthComputable) {
                            const percent = Math.round((event.loaded / event.total) * 100);
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            const totalMB = (event.total / 1024 / 1024).toFixed(2);
                            toast.update(percent, `${loadedMB} MB / ${totalMB} MB (${percent}%)`);
                        } else {
                            // 无法获取总大小时显示已下载量
                            const loadedMB = (event.loaded / 1024 / 1024).toFixed(2);
                            toast.update(50, `已下载 ${loadedMB} MB...`);
                        }
                    }
                });
                
                if (!res || !res.ok) throw new Error('请求失败,status=' + (res && res.status));
                
                toast.update(100, '处理文件中...');
                
                const arrayBuffer = res.response;
                const blob = new Blob([arrayBuffer], { type: 'video/mp4' });
                const objectUrl = URL.createObjectURL(blob);
    
                const link = document.createElement('a');
                const now = new Date();
                const dateStr = now.toISOString()
                    .slice(0, 19)
                    .replace('T', '_')
                    .replace(/:/g, '-');
                link.download = filename || `RWater_${dateStr}.mp4`;
                link.href = objectUrl;
                link.target = '_blank';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
    
                URL.revokeObjectURL(objectUrl);
                
                toast.success('视频已开始下载');
                toast.remove(1000);
            } catch (e) {
                console.error('下载失败:', e);
                toast.error(e.message || '下载失败,请重试');
                toast.remove(2000);
            }
        }
        /**
         * 初始化即梦网站的功能
         */
        function initJimengSite() {
            const observer = new MutationObserver(() => {
                jimeng_addVideoDownloadButton();
            });
    
            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['style', 'class']
            });
    
            // Also add event listeners for mouse interactions that might trigger UI changes
            document.addEventListener('mouseover', () => {
                setTimeout(() => {
                    jimeng_addVideoDownloadButton();
                }, 100);
            }, true);
    
            console.log('即梦: 初始化无水印下载工具');
            jimeng_addVideoDownloadButton();
        }
    
        /**
         * 创建即梦视频下载按钮
         * @returns {HTMLElement} 下载按钮元素
         */
        function jimeng_createVideoDownloadButton() {
            const button = document.createElement('div');
            button.className = 'lv-btn lv-btn-secondary lv-btn-size-default lv-btn-shape-square baseButton-LQGhrC download-btn';
            const div = document.createElement('div');
            div.textContent = '下载无水印视频';
            button.appendChild(div);
    
            button.title = '无水印下载';
            button.style = '--right-padding: 14px; align-items: center;background-color: var(--bg-block-primary-default); border-radius: 8px; color: var(--text-primary, #f5fbff); display: flex; font-family: PingFang SC;font-size: 12px; font-weight: 400; gap: 4px; justify-content: center; line-height: 20px; padding: 8px var(--right-padding) 8px 12px; position: relative;'
            return button;
        }
    
        function jimeng_getVideoDataId(downloadBtn) {
            console.log('即梦: 开始查找视频元素...');
            const parentItem = downloadBtn.closest('[class*="item-"]');
            return parentItem ? parentItem.getAttribute('data-id') : null;
        }
        /**
         * 获取即梦视频URL
         * @param {Element} downloadBtn - 下载按钮元素
         * @returns {string|null} 视频URL或null
         */
        function jimeng_getVideoUrl(downloadBtn) {
            console.log('即梦: 开始查找视频元素...');
            const parentItem = downloadBtn.closest('[class*="item-"]');
    
            const videoWrapper = parentItem.querySelector('div[class^="video-node-wrapper-"]');
            if (!videoWrapper) {
                alert('未找到视频');
                console.log('即梦: 未找到videoWrapper');
                return null;
            }
    
            let videoElement = videoWrapper.querySelector('video');
            if (!videoElement) {
                alert('未找到视频');
                console.log('即梦: 未找到video元素');
                return null;
            }
    
            if (videoElement && videoElement.src) {
                console.log('即梦: 找到视频元素:', {
                    src: videoElement.src,
                    className: videoElement.className,
                    width: videoElement.width,
                    height: videoElement.height,
                    naturalWidth: videoElement.naturalWidth,
                    naturalHeight: videoElement.naturalHeight,
                    attributes: Array.from(videoElement.attributes).map(attr => `${attr.name}="${attr.value}"`).join(', ')
                });
                return videoElement.src;
            }
    
            alert('未找到视频');
            console.log('即梦: 未找到合适的视频');
            return null;
        }
    
        /**
         * 添加视频下载按钮到即梦页面
         */
        function jimeng_addVideoDownloadButton() {
            const videoContents = document.querySelectorAll('div[class^="video-record-"]');
            if (!videoContents || videoContents.length === 0) {
                return;
            }
            for (let i = 0; i < videoContents.length; i++) {
                const topActionBar = videoContents[i].querySelector('div[class^="record-bottom-slots-"]');
                if (!topActionBar) {
                    continue;
                }
                if (topActionBar.querySelector('div[class^="image-record-content-"]')) {
                    continue;
                }
                if (topActionBar.querySelector('.download-btn')) {
                    continue;
                }
                jimeng_processSingleVideoButton(topActionBar);
            }
        }
    
        /**
         * 处理单个视频按钮(已简化:不再依赖 jimengVideoMap)
         * @param {Element} topActionBar - 操作栏元素
         */
        function jimeng_processSingleVideoButton(topActionBar) {
            const downloadBtn = jimeng_createVideoDownloadButton();
            topActionBar.insertBefore(downloadBtn, topActionBar.firstChild);
            console.info('即梦: 添加视频下载按钮');
    
            downloadBtn.addEventListener('click', async () => {
                console.log('即梦: 点击视频下载按钮');
                const videoDataId = jimeng_getVideoDataId(downloadBtn);
                const videoUrl = jimeng_getVideoUrl(downloadBtn);
                console.log('即梦: 获取到的视频URL:', videoUrl);
                let finalUrl = videoUrl;
    
                try {
                    // 2) 若仍然没有 finalUrl,尝试用 videoDataId 从 jimengDataMap 中查找 main_url
                    if (videoDataId) {
                        const cached = getJimengData(videoDataId);
                        if (cached) {
                            const extracted = extractMainUrlFromData(cached);
                            if (extracted) {
                                finalUrl = extracted;
                                console.log('即梦: 从 jimengDataMap 提取到 main_url,使用该 URL 下载', finalUrl);
                            }
                        }
                    }
    
                    if (!finalUrl) {
                        alert('未找到可下载的视频链接');
                        console.error('即梦: 未能解析出有效的下载 URL');
                        return;
                    }
    
                    downloadBtn.style.opacity = '0.5';
                    downloadBtn.style.pointerEvents = 'none';
                    await downloadVideo(finalUrl);
                } catch (e) {
                    console.error('即梦: 下载过程中出错', e);
                    alert('下载失败,请重试(查看控制台以获得更多信息)');
                } finally {
                    downloadBtn.style.opacity = '1';
                    downloadBtn.style.pointerEvents = 'auto';
                }
            });
        }
    
        initJimengSite();
    })();

    ![[第二弹] Nano Banana 新玩法!附带提示词!(懒人必备...)](https://xiaohack.oss-cn-zhangjiakou.aliyuncs.com/typecho/2025/11/2671742069.png!mark)
    Nano Banana 图片生成,又有新玩法,并且非常火爆,这里重新整理了第二波 Nano Banana 神级指令词,希望对大家有用!
    第一次:
    [bspost cid="5068"]
    Nano banana 使用渠道: https://imini.com/nano-banana

    玩法一:运动风个人写真 (哄女朋友开心)

    运动风个人写真提示词
    提示词:

    参考我上传的照片,输出一张高分辨率彩色艺术人像摄影,与照片不同的姿势,真实摄影。 主体是一位年轻女性,高马尾造型,几缕鬓发自然垂落,身材高挑,腰臀比例完美,马甲线清晰,双腿修长。她身穿白色高腰紧身运动背心,灰色短款瑜伽裤、白色长筒袜与白色老爹鞋,造型简洁又具力量感。 人物坐在白色桌面的边缘,身体微微向镜头扭转,右手后撑在桌面上保持平衡,左手举着一只切割纹理的玻璃杯,轻轻靠近锁骨位置。左腿弯曲收于身前,右腿自然向前下方伸展,脚尖轻点地面。她的头部微微上扬,眼神柔和自信,唇角轻扬,微笑自然不过分夸张,流露出轻松与优雅。 环境为纯白色摄影棚空间,墙地一体,极简留白。一张白色桌子是画面核心道具,桌面与墙面反射自然光形成高调干净的视觉平衡。玻璃杯与桌面上呈现出细微的高光反射与窗格投影,使画面更具空间感与真实光影层次。 光线来自左前上方的大型漫射窗光作为主光,整体为高调明亮的自然光氛围,皮肤高光细腻且层次分明。右侧以大白板反光轻柔填充,平衡暗部细节;右后方加入极弱的轮廓光,勾勒出发髻与肩背线条,使人物从背景中轻微分离。桌面上斜向延伸的窗格阴影柔和自然,为纯白场景增添节奏与层次。整体对比度中等,白平衡略偏冷,控制高光不过曝,保持通透而克制的质感。 带有轻微的雕塑感与时尚的克制力量。搭配 85mm 定焦镜头;机位略低,与桌面形成 5–10° 的轻微俯视角度。微提对比与清晰度,保持自然与质感的平衡。 能看到微小毛孔与柔细汗毛;颈部与肩膀的体积光顺滑自然;玻璃杯表面的高光折射逼真;窗格阴影的几何形状清晰而柔和。整体叠加轻微胶片颗粒,提升真实肤感与现代时尚氛围。 比例为 3:4 。

    玩法二:But love pray for me

    But love pray for me*

    这个玩法最近蛮火的,非常有创意。并且效果极好。

    提示词:

    上传图片的人物向前伸出拳头,拳头居于画面中间位置,无名指上戴着一枚金色戒指。戒指左侧有白色手写体英文“But love”,右侧有白色手写体英文“Pray for me”,两段英文与戒指处于同一水平线且紧密挨着。背景呈暖色调,整体风格为写实摄影,画面长宽比协调,营造出一种聚焦于拳头和戒指细节的视觉效果。

    玩法三:苹果高管风 工作照

    苹果高管风 工作照提示词

    “LinkedIn-style executive headshot, half-body (chest-up); face straight to camera, body slightly angled; calm, confident micro-smile. Wavy hair neatly styled; black sleeveless dress; minimalist professional look. Tight framing to emphasize facial features; eyes tack-sharp; natural skin texture. Soft directional lighting with subtle catchlights. Background: light-gray smooth gradient with clean separation. ( Create 4 variations with small pose/expression changes.) --no text, logos, busy patterns, heavy retouching, clutter 。

    ps:刚才这个提示词是生成四宫格照片的,如果大家只想要一张照片,把括号里的文字删掉就可以啦~”

    玩法四:韩系照片 堪比海马体效果

    韩系照片 堪比海马体效果提示词

    提示词:(上传图片最好清晰一点)

    Studio portrait of a young East Asian woman with long black hair, wearing an off-shoulder cream - colored top. She holds strawberries and grapefruit slices as props. Soft natural lighting, clean white background, fresh makeup with pink blush, 8K ultra - realistic, cinematic composition, aesthetic and minimalist.Professional studio lighting, softbox illumination, off - shoulder cream top, flowing black hair, strawberries and grapefruit slices as props, clean white background, shallow depth of field, 8K resolution, ultra - detailed skin texture, fresh makeup with pink blush and glossy lips, cinematic color grading, aesthetic composition, minimalist photography.

    玩法五:Q 版萌萌头像

    Q 版萌萌头像提示词

    提示词:

    把这张照片设计成一个 3D 风格 Q 版 APP 图标,保留人物特征,尤其是精细的五官。采用柔和且鲜明的打光风格,使其呈现出精致的高品质效果。角色应略微超出应用图标的边框,以增强 3D 效果和趣味性。确保人物五官与原照片一致,风格应给人一种值得收藏且萌趣可爱的感觉,类似于迷你手办或黏土人。

    玩法六:衣服穿搭

    衣服穿搭提示词

    提示词:

    选择图 1 中的人,让他们穿上图 2 中的所有服装和配饰。在户外拍摄一系列写实的 OOTD 风格照片,使用自然光线,时尚的街头风格,清晰的全身镜头。保持图 1 中人物的身份和姿势,但以连贯时尚的方式展示图 2 中的完整服装和配饰

    Nano Banana 使用方法:

    1.打开 imini: https://imini.com/nano-banana

    2.上传图片+输入指令等待图片生成即可。

    Nano Banana 使用方法