前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我的大AI网站上线了!

我的大AI网站上线了!

作者头像
zz_jesse
发布2024-06-17 12:57:53
840
发布2024-06-17 12:57:53
举报
文章被收录于专栏:前端技术江湖前端技术江湖

我的第一个网站:大前端面试题库 bigerfe.com

今天说说我的第二个网站。

--------------------------------------

之前一直想做个网站,反正五一也不出去,正好这几天可以开发一下。

为了尽快上线,有些功能让Ai来实现的,没想到1天就搞完了。

太快乐了!🎉

做的什么?

从去年开始,Ai领域突飞猛进的发展,国内各种大模型以及Ai应用层出不穷,不计其数,但是我们能了解到的也就阿里、百度、腾讯、字节等这些大厂的AI应用,但是仍然有很多优秀的应用大家无法接触到,更无法使用到。

所以打工人急需一个AI工具导航网站,方便打工人更快速便捷的找到目标应用,同时也能了解到更多其他AI应用,提高我们打工人的效率。

下面是我用1天时间开发的AI导航网站:

网址:dai.bigerfe.com

技术选型

  • 必须考虑SEO,因为要获取自然流量
  • 内容更新频率较低,谁没事会改简介,logo啥的,所以管理后台也不太需要
  • 考虑到我的服务器,空间有限,资源有限,所以框架啥的也不适用,不然装一堆npm依赖,给我磁盘干爆了

综上,最后决定使用最成熟,最没有新意的技术 😳。

node+Ai+koa2+ejs+bootstrap3+jQuery+file系统+pm2+ng+图床

整体思路

首先需要考虑数据源从哪来,导航网站的数据说多不多,说少不少,一条条添加,能把人干报废了。

还是找一个好点的网站,爬一爬吧,不过这样的网站大多数都是服务的直出。

目标网站就不说了,市面上有很多。

  • 数据源集合,也就是拿到网站Ai分类信息以及分类对应的页面url,还有分类页面是否有分页,要落地成一个配置文件
  • 详情页面不需要提前获取,每次打开页面时即时保存文件即可,下次访问走文件读取
  • 跳转到目标应用官网,不需要提前获取,访问时需要简单识别下html meta标签

为了提高效率,有些功能必须让AI来完成。

分类信息页面url

一个分类下对应多子分类,每个子分类的url,以及子分类列表还有分页。

这里借助了Kimi - AI 来处理,把页面的分类html输入给Kimi,再输入一些规则和要求,让他输出json格式的数据,包括分类名称,分类别名(用来当作路由),远程地址。

如下:

下面这些分类很多,手动整理很费时间,起码得2个小时,让Ai只需要半个小时。不过有训练不出来的风险。

代码语言:javascript
复制
//分类信息
module.exports = [
   {
    typeName: 'Ai工具箱',
    typeId:0,
    alias:'ai-write',
    child:[
        {
            typeName: 'Ai写作对话',
            update:false,
            alias:'ai-write',
            remote:['https://www.xxx.com/ai-write/','https://www.xxx.com/ai-write/list_664_2/'],
            items:[]
        },
        {
            typeName:'Ai绘画生成',
            alias:'ai-image',
            update:false,
            remote:['https://www.xxx.com/ai-image/','https://www.xxx.com/ai-image/list_660_2/'],
            items:[]
        },
        {
            typeName:'Ai视频生成',
            alias:'ai-shipin',
            update:false,
            remote:['https://www.xxx.com/ai-shipin/'],
            items:[]
        }
        ]
  }
  ]
  ......

Ai应用列表获取

这里就必须要使用cheerio了 ,可以在node里像使用jq一样获取数据。需要排除一些干扰信息,找到每个item的关键信息过滤就行。

代码语言:javascript
复制
//获取页面里的列表网站
async function execPageHtml(pageHtml) {
    // 使用cheerio加载HTML字符串
    const $ = cheerio.load(pageHtml);
    // 选取并提取h1标签中的文本内容
    const itemBoxs = $('.line-big');
    let lastResult = [];
    for (let i = 0; i < itemBoxs.length; i++) {
        const list = await getSiteBaseInfo(itemBoxs[i], $);
        lastResult = lastResult.concat(list);
    }
    return lastResult;
}

//获取网站的基本信息 title、url、logo、简介
async function getSiteBaseInfo(itemBox, $) {
    const result = [];
    const items = $(itemBox).find('a');
    for (let i = 0; i < items.length; i++) {
        const target = $(items[i]);
        const url = target.attr('href');
        //图片上传到七牛,下面说
        const imgInfo = await qiniu.uploadRemote($(target.find('img')[0]).attr('src'));
        if (url.indexOf('/site/') > -1) { //必须是站点
            const obj = {
                title: $(target.find('strong')[0]).text(),
                url,
                img: imgInfo ? imgInfo.key : '',
                desc: $(target.find('.text-default')[0]).text(),
                originId: url.substring(url.lastIndexOf('/') + 1).replace('.html', '')
            };
            result.push(obj);
        }
    }
    return result;
}

数据存储

网站列表不经常更新,也没必要搞个管理后台,所以在完成上面步骤后都会写入文件。

规则是按照分类别名存储:

代码语言:javascript
复制
function saveConToFile(filename, obj) {
    fs.writeFile(path.resolve(__dirname, `./data/${filename}.txt`), JSON.stringify(obj), (err) => {
        if (err) throw err;
        console.log('文件写入成功!');
    });
}

图片存储

有个两个图片需要进行处理,内容抄人家的,图片再用人家的,这老脸真挂不住了~。

  • 列表的logo图
  • 详情页的图片

其实想过放在自己的服务器上,但想了下不至于这么想不开吧。虽然很容易,但并不正确。

最后,放在七牛,还有些免费的空间,足够用了。

这种云平台,有非常完善的sdk,可以辅助开发者快速对接。

还能够直接读取远程图片直接保存,返回远程预览地址,真的香。

代码语言:javascript
复制
1. 需要先安装 qiniu npm包
2. 需要配置accessKey、secretKey、bucket
3. 需要获取 uploadToken

const qiniu = require('qiniu');
const path = require('path');
const encode = require('./encode');
var accessKey = 'xxxxxxsYzzzRcxhNMXV0dQJTtDrK';
var secretKey = 'xxxxxxV_-xNoqXAt8Uqkim'
var bucket = 'xxxxx';
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
var putPolicy = new qiniu.rs.PutPolicy({
    scope: bucket
});

var uploadToken = putPolicy.uploadToken(mac);

async function uploadRemote(remoteUrl,isMd5Name = true) {
    if(!remoteUrl) return '';
    let config = {
        // 空间对应的机房
        //zone: qiniu.zone.Zone_z1,
        // 是否使用https域名
        useHttpsDomain: false,
        // 上传是否使用cdn加速
        useCdnDomain: true
    }
    var bucketManager = new qiniu.rs.BucketManager(mac, config);
    var resUrl = remoteUrl;
    var bucket = "appandroid";
    var fileType = remoteUrl.substring(remoteUrl.lastIndexOf('.'));
    var key =  remoteUrl.substring(remoteUrl.lastIndexOf('/') + 1);
    if(isMd5Name){
        key = encode.md5(key) + fileType;
    }
    return new Promise(resolve=>{
        bucketManager.fetch(resUrl, bucket,'daai/' + key, function(err, respBody, respInfo) {
            if (err) {
              console.log(err);
              resolve(null);
            } else {
              if (respInfo.statusCode == 200) {
                console.log(respBody.key);
                resolve(respBody);
              } else {
                resolve(null);
              }
            }
          });
    })
}
module.exports = {
    uploadRemote
}

图片懒加载

一个分类下的应用很多,上百条是有的,logo需要做下加载优化,不然页面打开特别慢。

这里直接问AI就可以了,马上给你结果:

代码语言:javascript
复制
$(document).ready(function() {
    var lazyImages = [];  
    $("img.js-lazy-load").each(function() {
        var img = $(this);
        lazyImages.push(img);
    });
 
    function loadImg(){
        var scrollTop = $(window).scrollTop();
        for (var i = lazyImages.length - 1; i >= 0; i--) {
            var img = lazyImages[i];
            if ((img.offset().top - $(window).height()) < scrollTop) {
                img.attr('src', img.attr('data-src'));
                lazyImages.splice(i, 1);
            }
        }
        if (!lazyImages.length) {
            $(window).off('scroll');
        }
    }

    $(window).scroll(function() {
       loadImg();
    });
    loadImg();

网站tdk

如果不设置TDK,爬虫可能无法知道你的网站做啥的。

  • 网站有主标题,在每一个页面的结尾

举例:

代码语言:javascript
复制
<title>懂AI | 一站式AI导航</title>
  • 关键词也一样

举例:

代码语言:javascript
复制
<meta name="keywords" content="Leonardo.ai,懂AI" />
  • 描述需要定制,根据每个页面定

所以这里需要搞一个中间件来处理通用的tdk对象,在ejs任何一个页面上都能获取。

定制的描述,就在他所属的controller内改写。

看代码:

代码语言:javascript
复制
//commoninfo 中间件
module.exports= async function (ctx,next) {
    //获得基础通用数据并绑定到 ctx 上
    ctx.CommonInfo = {
        tdk:{
            title:'ai人工智能,gpt人工智能,大Ai工具导航',
            key:'大Ai工具导航',
            desc:'大Ai工具导航是一个不断增长的AI人工智能工具资源库,xxxx'
        }
    };
    await next();
}

在搜索controller内重写。

代码语言:javascript
复制
module.exports = async (ctx) => {
   const { key = '' } = ctx.query;
   ctx.CommonInfo.tdk.title = '搜索-' + key;
   const links = await searchApp(key);
   ejsRender.call(ctx, 'newpages/search/search.html', {
      ...ctx.CommonInfo,
      links: links || [],
      skey: key
   });
}

搜索

我用的最多的就是搜索,能很快定位到目标网站。

搜索就比较暴力了,根据路径配置,和本地文件内容,计算出全集,然后进行过滤。

更好的是加个缓存,没必要每次都重新读取,浪费资源(当有了自己的服务器,每个资源都是非常宝贵的)。

代码语言:javascript
复制
//url配置
module.exports = [
   {
    typeName: 'Ai工具箱',
    typeId:0,
    alias:'ai-write',
    child:[
        {
            typeName: 'Ai写作对话',
            update:false,
            alias:'ai-write',
            remote:['https://www.xxx.com/ai-write/','https://www.xxx.com/ai-write/list_664_2/'],
            items:[]
        },
        {
            typeName:'Ai绘画生成',
            alias:'ai-image',
            update:false,
            remote:['https://www.xxx.com/ai-image/','https://www.xxx.com/ai-image/list_660_2/'],
            items:[]
        },
        {
            typeName:'Ai视频生成',
            alias:'ai-shipin',
            update:false,
            remote:['https://www.xxx.com/ai-shipin/'],
            items:[]
        }
        ]
  }
  ]
代码语言:javascript
复制
//搜索方法
async function searchApp(key) {
   if(!allAppInfo.length){
      for (let i = 0; i < urlConfig.length; i++) {
         const len = urlConfig[i].child.length;
         const childs = urlConfig[i].child;
         for (let j = 0; j < len; j++) {
            const child = childs[j];
            const alias = child.alias;
            const linksStr = fs.readFileSync(path.resolve(__dirname, '../common/data/'+alias+'.txt'));
            const list = JSON.parse(linksStr);
            allAppInfo = allAppInfo.concat(list);
         }
      }
   }
   return allAppInfo.filter(item=>item.title.indexOf(key)>-1 || item.desc.indexOf(key)>-1);
}

部署

这里直接使用pm2+nginx即可。

但是端口得是能自定义,从命令中传递过去。

代码语言:javascript
复制
//获取端口
const port = process.env.PORT || config.defaultPort
//pm2命令
PORT=7560 pm2 start app.js -n bigai-7560 -o --watch -- env:production

最后

网站就介绍到这里,技术很古老,再结合下AI,效率真的高,我的宗旨就是稳定,好用就ok。

也可以点击左下角原文链接来体验下。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端技术江湖 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 做的什么?
  • 技术选型
  • 整体思路
  • 分类信息页面url
  • Ai应用列表获取
  • 数据存储
  • 图片存储
  • 图片懒加载
  • 网站tdk
  • 搜索
  • 部署
  • 最后
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档