本文作者为 360 奇舞团前端开发工程师
众所周知,《奇舞精选》目前有两个在运营的粉丝群,小编会不定期在群里分享一些关于 AI 或前端相关的最新资讯或开源项目,这些分享内容的一个来源就是 GitHub Trending:https://github.com/trending。为了提高阅读效率,小编开发了一个自动抓取 GitHub Trending 页面内容并通过大模型 Moonshot(月之暗面即 Kimi)翻译总结成中文的工具。本文详细介绍了小工具开发过程和遇到的问题及解决方案,最后附项目源码。
目标 自动抓取 GitHub Trending 仓库列表。 使用 MoonShot API 总结每个仓库的简介。 下面这个页面即最终的运行效果,小编还贴心的加上了暗黑模式。
功能需求:
技术选型:
前端框架 :Next.js、Tailwind CSSAPI 服务 :GitHub API, MoonShot API为什么选择 MoonShot API?因为 MoonShot API 对于新注册用户有一定的免费额度,且和 OpenAI 兼容,如果想迁移到 OpenAI 也非常方便。
技术实现
初始化 Next.js 项目 首先,我们使用以下命令创建一个 Next.js 项目:
npx create-next-app@latest
✔ What is your project named? … github-trending ✔ Would you like to use TypeScript? … No / Yes ✔ Would you like to use ESLint? … No / Yes ✔ Would you like to use Tailwind CSS? … No / Yes ✔ Would you like to use `src/` directory? … No / Yes ✔ Would you like to use App Router? (recommended) … No / Yes ✔ Would you like to customize the default import alias (@/*)? … No / Yes
初始化完项目并安装依赖后,yarn dev
启动项目。
获取 GitHub Trending 数据 由于 GitHub API 没有专门的 Trending API,我们需要通过 GitHub Trending 页面获取数据,可以使用 Puppeteer 或 Cheerio 进行页面抓取,这里我们选择 Cheerio。
Cheerio 是一个快速、灵活、轻量级的 JavaScript 库,专门用于在 Node.js 环境中操作和解析 HTML。它提供了一种类似于 jQuery 的 API,使得开发者可以方便地对 HTML 结构进行查询、修改等操作。
yarn add cheerio
抓取 GitHub Trending 的代码可以如下实现:
// app/page.js import { load } from "cheerio"; const fetchTrendingRepos = async () => { try { const res = await fetch("https://github.com/trending?since=daily"); const htmlText = await res.text(); const $ = load(htmlText); const repos = []; const elements = $("h2.h3.lh-condensed"); for (const element of elements) { // 从 html 里解析出 repoName const repoName = $(element).find("a").attr("href").trim().substring(1); console.log("repoName", repoName); const repoDetail = await fetchRepoDetail(repoName); if (!repoDetail) continue; const translatedDescription = await translateDescription( repoDetail.description || "无描述" ); await delay(70 * 1000); const summary = await summarizeReadme(repoName); await delay(70 * 1000); repos.push({ name: repoName, desc: translatedDescription, summary, }); } return repos; } catch (error) { console.error("Error fetching trending repositories:", error); return []; } };
获取仓库详情 上面的代码解析出仓库名,接下来我们就可以调 GitHub API 来获取仓库详情了:
const fetchRepoDetail = async (repoName) => { try { const response = await fetch(`https://api.github.com/repos/${repoName} ` ); if (!response.ok) throw new Error ("Failed to fetch repo details" ); return await response.json(); } catch (error) { console .error(`Error fetching repo details for ${repoName} :` , error); return null ; } };
GitHub API 也有访问限制,对于未认证的请求:每小时的请求限额:60 次。对于认证的请求:每小时的请求限额:5000 次。
翻译 description 成中文 拿到详情,我们用大模型把 description 翻译成中文。因为 MoonShot 兼容 OpenAI SDK,因此我们先添加 OpenAI SDK 依赖。
yarn add openai
然后引入并添加配置:
import OpenAI from "openai" ;const client = new OpenAI({ apiKey : process.env.MOONSHOT_API_KEY, //需要注册后申请 baseURL : "https://api.moonshot.cn/v1" , });
最后调用 chat 来进行翻译:
const translatedDescription = await translateDescription( repoDetail.description || "无描述" );const fetchMoonShotResponse = async (content, role) => { try { const completion = await client.chat.completions.create({ model : "moonshot-v1-8k" , messages : [ { role : "system" , content : role, }, { role : "user" , content, }, ], temperature : 0.3 , }); return completion.choices[0 ].message.content; } catch (error) { console .error("Error in request:" , error); return "" ; } };const translateDescription = async (description) => { return await fetchMoonShotResponse( `${description} 翻译成中文` , "你是翻译专家,擅长各种语言翻译" ); };
总结 Readme
const summarizeReadme = async (repoName) => { try { const response = await fetch( `https://api.github.com/repos/${repoName} /readme` ); if (!response.ok) throw new Error ("Failed to fetch readme" ); const readmeData = await response.json(); const readmeStr = atob(readmeData.content); return await fetchMoonShotResponse( `${readmeStr} 总结成200字的中文` , "你是翻译专家,擅长各种语言翻译和总结" ); } catch (error) { console .error(`Error summarizing README for ${repoName} :` , error); return "" ; } };
注意,对于免费用户 MoonShot 也有请求限制,因此,每次调用 MoonShot 后,需要增加 delay 避免频繁请求接口。参见:https://platform.moonshot.cn/docs/pricing/limits
用户等级 累计充值金额 并发 RPM TPM TPD Free ¥ 0 1 3 32,000 1,500,000 Tier1 ¥ 50
50 200 128,000 10,000,000 Tier2 ¥ 100 100 500 128,000 20,000,000 Tier3 ¥ 500 200 5,000 384,000 Unlimited Tier4 ¥ 5,000 400 5,000 768,000 Unlimited Tier5 ¥ 20,000 1,000 10,000 2,000,000 Unlimited
以上我们就有了要展示在前端的所有数据:
前端展示
前端展示我们使用 Tailwind CSS 官方插件typography
,它简化了为文章、博客等长内容应用默认样式的过程,使文本更具可读性和美感。通过 prose
类来为内容块提供一组经过精心设计的排版样式。以下是详细用法和常见场景:
安装
首先,你需要在你的 Tailwind CSS 项目中安装 @tailwindcss/typography
插件:
yarn add @tailwindcss/typography
然后,在 tailwind.config.js
中引入该插件:
module .exports = { plugins : [ require ('@tailwindcss/typography' ), ], }
基本用法
使用 prose
类可以让一整块内容的排版看起来更统一。例如:
<div class ="prose" > <h1 > Tailwind CSS Typographyh1 > <p > 这是一个段落,包含了默认的 <code > prosecode > 样式。这些样式会自动应用到标题、段落、列表、引用等元素上。p > <blockquote > 这是一个引言。blockquote > <ul > <li > 第一项li > <li > 第二项li > <li > 第三项li > ul >div >
此时,prose
类会对其中的 h1
、p
、blockquote
和 ul
等 HTML 元素应用默认的样式。
修改字体颜色和尺寸
也可以结合其他 Tailwind 的工具类对排版样式进行进一步自定义,例如改变字体颜色或尺寸:
<div class ="prose prose-lg text-gray-700" > <h1 > 较大字体的文章标题h1 > <p > 段落文字将应用灰色字体。p >div >
text-gray-700
将文本颜色设置为深灰色。我们最终展示的代码如下:
export default async function Home ( ) { const repos = await fetchTrendingRepos(); return ( <div > <h1 className ="mt-10 text-4xl font-bold leading-tight" > Welcome to{" "} <a href ="https://github.com/trending" className ="text-[#0070f3] hover:underline focus:underline active:underline" > Trending Repositories! a > h1 > <div className ="prose dark:prose-invert" > {repos.map((repo, index) => ( <article key ={index} > <Link href ={ `https: //github.com /${repo.name }`}> <h2 > {repo.name}h2 > Link > {repo.desc && ( <p className ="text-sm text-gray-500 dark:text-gray-400" > 描述:{repo.desc} p > )} {repo.summary && ( <p className ="font-semibold italic" > AI总结: {repo.summary}p > )} article > ))} div > div > ); }
总结 通过本教程,我们已经实现了一个基于 Next.js 和 MoonShot API 的 GitHub Trending 总结工具。它不仅展示了 Next.js 的强大特性,还结合了 MoonShot 大模型的能力。可以帮助小编快速掌握热门趋势并更高效地获取信息。当然目前本项目停留在自用阶段,仍有较大的优化空间。例如将定时更新数据并存到数据库等,后续小编会逐步完善次项目。
源码地址 https://github.com/yangpeng7/github-trending
参考 https://docs.github.com/en/rest
https://github.com/tailwindlabs/tailwindcss-typography
https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28