惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
A
Arctic Wolf
Security Latest
Security Latest
雷峰网
雷峰网
V2EX - 技术
V2EX - 技术
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Schneier on Security
WordPress大学
WordPress大学
J
Java Code Geeks
宝玉的分享
宝玉的分享
T
The Exploit Database - CXSecurity.com
T
Troy Hunt's Blog
Scott Helme
Scott Helme
爱范儿
爱范儿
罗磊的独立博客
Apple Machine Learning Research
Apple Machine Learning Research
Application and Cybersecurity Blog
Application and Cybersecurity Blog
I
Intezer
博客园 - 【当耐特】
T
Threat Research - Cisco Blogs
L
LINUX DO - 最新话题
W
WeLiveSecurity
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
IT之家
IT之家
N
News and Events Feed by Topic
The Hacker News
The Hacker News
Know Your Adversary
Know Your Adversary
小众软件
小众软件
博客园 - 叶小钗
Latest news
Latest news
P
Proofpoint News Feed
G
GRAHAM CLULEY
Schneier on Security
Schneier on Security
T
Tor Project blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Project Zero
Project Zero
The Cloudflare Blog
美团技术团队
大猫的无限游戏
大猫的无限游戏
S
Secure Thoughts
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
Jina AI
Jina AI
V
Visual Studio Blog
Help Net Security
Help Net Security

十月指南

使用AI开发一个应用最好的时间是现在 Kimi K2 发布并开源,实测效果确实很强! Vibe Coding实战:从翻车到上线,我开发了一款提前还贷计算器小程序 告别熬夜写代码!AI编程让我用Vibe Coding轻松上线 10 + 工具 用Vibe Coding方式打造 AI 内容创作平台 我连代码都没写,却做出JSON格式化工具—Vibe Coding了解一下 GPT 4.1、DeepSeek R1、Claude 3.7 代码生成横评,谁才是设计稿还原之王? AI 时代程序员生存指南 Cursor+Figma MCP 设计稿还原如此简单 MCP(模型上下文协议)是什么?它如何简化与API的AI集成 号外!我用Trae+Claude3.7开发的小程序上线啦 30分钟开发完成!Trae+Claude 3.7 打造小程序全流程揭秘! 5 分钟打造超酷小程序设计稿,Trae+Claude 3.7 太神了! 一句话生成设计稿,Trae+Claude 3.7 Sonnet,设计师也要被AI取代了 一句话生成应用!程序员效率翻倍的AI代码生成工具大盘点 我用AI创作了一首歌:Suno、海绵音乐、天工AI音乐生成效果测评 从哪吒2热潮到AI短片创作:AI视频实战测评 shadcn_ui:2024年最受欢迎的前端项目 技术篇:构建与部署 技术篇:Google 统计服务 技术篇:Next.js 多环境配置 技术篇:数据库-Prisma 技术篇:身份验证-NextAuth 技术篇:CSR、SSR、SSG、ISR 与客户端、服务端组件 技术篇:Next.js 路由与页面管理 技术篇:Next.js 项目结构 技术篇:Next.js 简介与概览 技术篇:从零开始掌握 Tailwind CSS 设计篇:独立开发设计入门 开篇:走上独立开发之路 Ollama:本地大模型运行指南 TooTool.net 理解 CSS 中的 Containing Block(包含块) 独立开发者工具大全(持续更新) TimeFlow 如何快速拥有一个技术博客 一个人从零开发上线一款App需要多少钱?终于有答案了! 深入理解HTTPS Nginx实战 Flutter Platform Channel 使用与源码分析 Android SDK类产品开发总结 360插件化框架 RePlugin 之 ClassLoader Hook Mac下Charles抓包配置 十一大西北体验 利用ContentProvider实现同步Binder macOS修改Android模拟器Hosts 走过 登山记 期待成长 小雨 静夜思 关于
实战:基于 Next.js+MoonShot API 开发一个 Github Trending 总结助手
十月 · 2025-02-10 · via 十月指南

目标 #

  • 自动抓取 GitHub Trending 仓库列表。
  • 使用 MoonShot API 总结每个仓库的简介。
  • 展示一个用户友好的界面,列出描述和简介。

下面这个页面即最终的运行效果,小编还贴心的加上了暗黑模式。

image.png
image <em>1</em>.png

功能需求:

  • 获取 GitHub Trending 数据。
  • 利用 OpenAI API 生成自然语言总结。

技术选型:

  • 前端框架:Next.js、Tailwind CSS
  • API 服务: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 结构进行查询、修改等操作。

抓取 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 次。

image <em>2</em>.png

翻译 description 成中文 #

拿到详情,我们用大模型把 description 翻译成中文。因为 MoonShot 兼容 OpenAI SDK,因此我们先添加 OpenAI SDK 依赖。

然后引入并添加配置:

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

以上我们就有了要展示在前端的所有数据:

  • repoName
  • description
  • summary

前端展示 #

前端展示我们使用 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 Typography</h1>
  <p>这是一个段落,包含了默认的 <code>prose</code> 样式。这些样式会自动应用到标题、段落、列表、引用等元素上。</p>
  <blockquote>这是一个引言。</blockquote>
  <ul>
    <li>第一项</li>
    <li>第二项</li>
    <li>第三项</li>
  </ul>
</div>

此时,prose 类会对其中的 h1pblockquoteul 等 HTML 元素应用默认的样式。

修改字体颜色和尺寸

也可以结合其他 Tailwind 的工具类对排版样式进行进一步自定义,例如改变字体颜色或尺寸:

<div class="prose prose-lg text-gray-700">
  <h1>较大字体的文章标题</h1>
  <p>段落文字将应用灰色字体。</p>
</div>
  • prose-lg 会增加内容的整体字体大小。
  • 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://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