Bing AI 生成每日图片

前段时间刷到一篇分享 liruifengv/daily-poetry-image:用Bing-AI的文生图功能结合诗词api生成对应图片。联想到之前fork的bing-wallpaper项目,就来简单改造下。

bing-wallpaper

bing-wallpaper项目比较简单,就是利用GitHub-action跑定时任务爬取Bing每日壁纸链接,随后更新README.md文档。

这个项目是用java写的,当时直接fork的niumoo/bing-wallpape,修改下ci的配置就能跑了。目前已经稳定运行快两年了,每天会跑两次防止更新遗漏,会有一次异常部署是因为当时还没更新今日壁纸。

改造的思路就是利用Bing-AI来代替Bing每日壁纸,每天都是AI-Generate图片。

bing-ai-poetry

Github 地址 Mulander-J/bing-ai-poetry

前提准备,需要有edge浏览器+账号,以及科学上网。能正常访问 https://bing.com/create,并生成一次图片,记录cookie后面会用到。

文生图的文字部分由今日诗词api随机生成。

bash 复制代码
curl https://v1.jinrishici.com/all

{
  "content" : "正蹇驴吟影,茶烟灶冷,酒亭门闭。",
  "origin" : "无闷·催雪",
  "author" : "吴文英",
  "category" : "古诗文-食物-写茶"
}

liruifengv/daily-poetry-image 的基础上,砍掉原有的前端项目(不需要前端渲染,自带README.md足够。)

diff 复制代码
- website

稍微修改入口文件 bin/cli.ts

之前在本地测试的时候,因为网络原因图片经常只能下到一两张,且只有一半的数据。修改的部分主要是将主函数套上async,然后就可以在内部await图片下载和读写事务,确保进程退出时图片不会下到一半。

另外下载好图片的同时会同步修改README.md文件,只需要append新内容就行了。

核心的getImageBySentence 随机诗词文生图方法原项目都封装好了。

ts 复制代码
import { getImageBySentence } from "../src/get-up";
import type { Response } from "../src/types";
import path from "path";
import fs from "fs";
import stream from "stream";
import { promisify } from "util";

const pipeline = promisify(stream.pipeline);

async function init() {
   const cwd = process.cwd();

   const argv = require("minimist")(process.argv.slice(2));
   if (argv.cookie && typeof argv.cookie !== 'boolean') { // 此处兼容 --cookie="xx" 和 --cookie "xx"
       try {
           // const res =  {
           //     images: [
           //         'https://tse1.mm.bing.net/th/id/OIG.0lT30AZgF0Y9TGnssoUu',
           //         'https://tse2.mm.bing.net/th/id/OIG.AYKgb1ftqrAfxCfwGjCs',
           //         'https://tse1.mm.bing.net/th/id/OIG.GcNrrihRgfhlHOwiRtR.'
           //     ],
           //     content: '关山别荡子,风月守空闺。',
           //     origin: '昔昔盐',
           //     author: '薛道衡',
           //     category: '古诗文-抒情-离别'
           // }
           const res: Response = await getImageBySentence(argv.cookie);
           console.log("Create Successful: ", res);

           const imagesPath = path.join(cwd, "images");
           if (!fs.existsSync(imagesPath)) {
               fs.mkdirSync(imagesPath);
           }

           // 在 images 目录下,创建一个以时间戳命名的文件夹,将图片放入其中
           const imagesFolderName = Date.now().toString();
           const imagesFolderPath = path.join(imagesPath, imagesFolderName);
           if (!fs.existsSync(imagesFolderPath)) {
               fs.mkdirSync(imagesFolderPath);
           }
           const images = res.images
           let imgPaths:any[] = []
           // 将图片放入 images 目录下的文件夹中
           for(let i = 0; i < images.length; i++){
                // images 中是网络url,请求图片,将图片保存到 images 目录下的文件夹中
               const imageFileName = `${i}.jpg`;
               const imageFilePath = path.join(imagesFolderPath, imageFileName);
               const imageDocPath = `./images/${imagesFolderName}/${imageFileName}`
               imgPaths.push(`![${imagesFolderName}_${imageFileName}](${imageDocPath})[${imageFileName}](${images[i]})`)

               // 下载图片
               console.log('fetching...', images[i])
               const res:any = await fetch(images[i])
               if (!res.ok) throw new Error(`unexpected response ${res.statusText}`);
               await pipeline(res.body, fs.createWriteStream(imageFilePath)).catch((e) => {
                   console.error("Something went wrong while saving the image", e);
               });
               console.log('>fetched', images[i])
           }
           console.log('Fetch Images Ended')

           const options = { timeZone: "Asia/Shanghai", hour12: false };
           const outputData = {
               ...res,
               date: new Date().toLocaleString("zh-CN", options),
               localImagesPath: imagesFolderName,
           };

           const contentFile = path.join(imagesFolderPath, 'index.json');

           fs.writeFileSync(contentFile, JSON.stringify(outputData));

           const rowHead = `> ${res.content} ------ ${res.author}《${res.origin}》\n`
           let appendCtx = `|${imgPaths.map(_=>'      ').join('|')}|\n`
           appendCtx += `|${imgPaths.map(_=>' :----: ').join('|')}|\n`
           appendCtx += `|${imgPaths.join('|')}|`
           fs.appendFileSync('./README.md', [
               '',
               rowHead,
               appendCtx,
               ''
           ].join('\n'))

           // 缓冲等待,确保未捕获的异步任务都能跑完
           console.log('Wating Sec...')
           setTimeout(() => {
               process.exit(0);
           }, 5 * 1000);
       } catch (e) {
           console.error(e);
           process.exit(1);
       }
   } else {
       throw new Error("Please provide a cookie using the --cookie argument");
   }
}

init().catch((e) => {
   console.error(e);
});

以及,处理Bing接口返回时,获取图片数据是采用正则/src="([^"]*)"/g全局匹配的,偶尔会跑出来几张https://r.bing.com/rp/xxx的乱入图片需要剔除。

ts 复制代码
    // /src/bing-image-creator.ts
    parseResult(result: string) {
        console.log("Parsing result...");
        // Use regex to search for src=""
        const regex = /src="([^"]*)"/g;
        const matches = [...result.matchAll(regex)].map((match) => match[1]);
        // Remove Bad Images(https://r.bing.com/rp/xxx)
        const safe_image_links = matches.filter(link => !/r.bing.com\/rp/i.test(link))
        // Remove size limit
        const normal_image_links = safe_image_links.map(link => (link.split("?w=")[0]));
        // Remove duplicates
        const unique_image_links = [...new Set(normal_image_links)];
        // No images
        if (unique_image_links.length === 0) {
            throw new Error("error_no_images");
        }
        return unique_image_links;
    }

完工。接下来就是actions定时跑任务了, 一切正常。

相关推荐
自由生长20246 分钟前
为什么我们需要流式系统?
前端
北辰alk11 分钟前
从零设计一个Vue路由系统:揭秘SPA导航的核心原理
前端·vue.js
鱼鱼块30 分钟前
彻底搞懂 React useRef:从自动聚焦到非受控表单的完整指南
前端·react.js·面试
nwsuaf_huasir1 小时前
积分旁瓣电平-matlab函数
前端·javascript·matlab
韭菜炒大葱1 小时前
React Hooks :useRef、useState 与受控/非受控组件全解析
前端·react.js·前端框架
Cache技术分享1 小时前
280. Java Stream API - Debugging Streams:如何调试 Java 流处理过程?
前端·后端
微爱帮监所写信寄信1 小时前
微爱帮监狱寄信写信小程序信件内容实时保存技术方案
java·服务器·开发语言·前端·小程序
沛沛老爹1 小时前
Web开发者实战A2A智能体交互协议:从Web API到AI Agent通信新范式
java·前端·人工智能·云原生·aigc·交互·发展趋势
这是个栗子1 小时前
【Vue代码分析】vue方法的调用与命名问题
前端·javascript·vue.js·this
全栈前端老曹1 小时前
【前端路由】Vue Router 动态导入与懒加载 - 使用 () => import(‘...‘) 实现按需加载组件
前端·javascript·vue.js·性能优化·spa·vue-router·懒加载