Skip to content

Commit

Permalink
✨ feat(last-modified): add new workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
summerscar committed Oct 27, 2024
1 parent 4aa4ba5 commit 06b19f0
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 97 deletions.
22 changes: 16 additions & 6 deletions .github/workflows/generate-doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Run script:docs
run: |
npm install
npm run script:docs-desc
- name: Install dependencies
run: npm install

- uses: stefanzweifel/git-auto-commit-action@v4
- name: Run script:docs-desc
run: npm run script:docs-desc

- name: Commit docs-desc
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "📃 docs(description): generate description by chatGPT"

- name: Run script:docs-modified
run: npm run script:docs-modified

- name: Commit docs-modified
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "📃 docs(content): edit by chatGPT"
commit_message: "📃 docs(last-modified): update doc last-modified"
10 changes: 8 additions & 2 deletions app/(home)/learn/[...doc_path]/_components/markdown-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
import { type ReactNode, useEffect, useState } from "react";
import type { TocItem } from "remark-flexible-toc";

const MDContentWrapper = ({ children }: { children: ReactNode }) => (
<article className="markdown-body p-8 border-r-2 border-slate-900/10 flex-auto">
const MDContentWrapper = ({
children,
lastModified,
}: { children: ReactNode; lastModified?: string }) => (
<article
data-last-modified={lastModified}
className="markdown-body p-8 border-r-2 border-slate-900/10 flex-auto"
>
{children}
</article>
);
Expand Down
9 changes: 8 additions & 1 deletion app/(home)/learn/[...doc_path]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ export default async function Page(props: { params: Promise<DocPathParams> }) {
const { doc_path: docPath } = params;
const docPathString = docPath.slice(1).map(decodeURIComponent).join("/");
const [mdx, toc] = await loadMDX(level, docPathString || "_intro");
const lastModified = new Date(
Number((mdx.frontmatter["last-modified"] as string) || 0) * 1000,
).toUTCString();

isDev && (await timeOut(500));

return (
<>
<MDContentWrapper>{mdx.content}</MDContentWrapper>
<MDContentWrapper lastModified={lastModified}>
{mdx.content}
</MDContentWrapper>
<Toc toc={toc} />
</>
);
Expand Down
1 change: 1 addition & 0 deletions mdx/beginner/键盘输入方法.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ author: summerscar
description: 这份韩语学习教程介绍了韩语键盘输入方法,包括了各个拼音字母对应的按键。教程还提供了一个练习页面供学习者进行练习。学习者可以通过按键的组合来输入特殊的韩语字母。总结而言,这份教程提供了详细的指导,帮助学习者掌握韩语键盘输入方法。
date: 0
tags: ['keyboard', 'hangul']
last-modified: 1729998432
---

## 韩语键盘输入方法
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"prepare": "husky",
"lint-staged": "lint-staged",
"script:docs-desc": "tsx scripts/generate-doc-desc.ts",
"script:docs-modify": "tsx scripts/generate-doc-last-modification.ts"
"script:docs-modified": "tsx scripts/generate-doc-last-modified.ts"
},
"dependencies": {
"@keystone-6/auth": "^8.0.0",
Expand Down
100 changes: 29 additions & 71 deletions scripts/generate-doc-desc.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { Levels } from "@/types";
import {
type FileItem,
_listAllDocs as _listAllDocsByLevel,
} from "@/utils/list-docs";
import { config as envConfig } from "dotenv";
import OpenAI from "openai";
envConfig({ path: ["./.env", "./.env.local"] });
import { _listAllDocs as _listAllDocsByLevel } from "@/utils/list-docs";
import { flattenAllDocs, insertOrUpdateFrontmatterKey } from "./list-all-docs";
import { fetchChatCompletion } from "./open-ai";

(async () => {
const DESC_MIN_LENGTH = 10;

const docs = await flattenAllDocs();
// console.log("[generate-doc-desc]: \n", docs);
// 筛序出文档中的 frontmatter 的 description 部分少于 DESC_MIN_LENGTH 个字的
const docsNeedToGenerateDescription = docs.filter((doc) => {
const docString = readFileSync(doc.path, "utf-8");
Expand All @@ -22,78 +15,43 @@ envConfig({ path: ["./.env", "./.env.local"] });
return description !== undefined && description.length < DESC_MIN_LENGTH;
});

console.log("[generate-doc-desc]: start...");
console.log(
"[generate-doc-desc]: start...\n",
docsNeedToGenerateDescription
.map((doc) => `【${doc.title}】...`)
.join("\n"),
"\namount: ",
docsNeedToGenerateDescription.length,
docsNeedToGenerateDescription.map((doc) => `[${doc.title}]...`).join("\n"),
);
console.log("[generate-doc-desc][find]: ↑↑↑↑↑↑↑↑↑↑↑↑");
await Promise.all(
docsNeedToGenerateDescription.map(async (doc) => {
if (doc.content === undefined) return;
const description = await fetchChatCompletion(doc.content);

console.log("[generate-doc-desc][title][", doc.title, "]: generate...");
const description = await fetchChatCompletion([
{
role: "user",
content:
"我将发你一份韩语学习相关教程,你将总结这份教程,生成的描述,控制在20-100个字。",
},
{
role: "user",
content: doc.content,
},
]);
if (!description) return;
console.log("[generate-doc-desc][title][", doc.title, "]: ", description);
console.log(
"[generate-doc-desc][title][",
doc.title,
"][update]: ",
description,
);
// 将 description 写入 frontmatter
const newDocString = doc.content.replace(
/description:(.*)/,
`description: ${description}`,
const newDocString = insertOrUpdateFrontmatterKey(
doc.content,
"description",
description,
);
writeFileSync(doc.path, newDocString, "utf-8");
console.log("[generate-doc-desc][title][", doc.title, "]: success!");
}),
);
console.log("[generate-doc-desc][all]: success!");
})();

export async function flattenAllDocs() {
const levels = [Levels.Beginner, Levels.Intermediate];

return (
await Promise.all(levels.map((level) => listAllDocsByLevel(level)))
).flat();
}

async function listAllDocsByLevel(level: string) {
const docs = await _listAllDocsByLevel(level);
const flattenDocs = docs
.flatMap((doc) => {
if ("children" in doc) {
return doc.children;
}
return doc;
})
.map((doc) => {
return {
title: doc.title,
path: join(process.cwd(), "mdx", level, (doc as FileItem).relativePath),
} as { title: string; path: string; content?: string };
});
return flattenDocs;
}

const openai = new OpenAI({
apiKey: process.env.GPT_KEY,
baseURL: process.env.GPT_URL,
});

async function fetchChatCompletion(docContent: string) {
const result = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{
role: "user",
content:
"我将发你一份韩语学习相关教程,你将总结这份教程,生成的描述,控制在20-100个字。",
},
{
role: "user",
content: docContent,
},
],
});
console.log(`[chatGPT]: use ${result.usage?.total_tokens} tokens.`);
return result.choices[0].message.content;
}
16 changes: 0 additions & 16 deletions scripts/generate-doc-last-modification.ts

This file was deleted.

30 changes: 30 additions & 0 deletions scripts/generate-doc-last-modified.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { exec, execSync } from "node:child_process";
import { readFileSync, writeFileSync } from "node:fs";
import { flattenAllDocs, insertOrUpdateFrontmatterKey } from "./list-all-docs";

(async () => {
const docs = await flattenAllDocs();
const docsWithLastModification = docs.map((doc) => {
const timeStamp = execSync(
`git log -1 --pretty="format:%ct" -- "${doc.path}"`,
).toString("utf-8");
return {
...doc,
lastModified: timeStamp,
};
});
docsWithLastModification.forEach((doc) => {
const docString = readFileSync(doc.path, "utf-8");
const frontmatterKey = "last-modified";
const newDocString = insertOrUpdateFrontmatterKey(
docString,
frontmatterKey,
doc.lastModified,
);
writeFileSync(doc.path, newDocString);
console.log(
`[generate-doc-last-modified]: ${doc.title} -> ${frontmatterKey}: ${doc.lastModified}`,
);
});
// console.log("[generate-doc-last-modification]: \n", docsWithLastModification);
})();
54 changes: 54 additions & 0 deletions scripts/list-all-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { join } from "node:path";
import { Levels } from "@/types";
import {
type FileItem,
_listAllDocs as _listAllDocsByLevel,
} from "@/utils/list-docs";

export async function flattenAllDocs() {
const levels = [Levels.Beginner, Levels.Intermediate];

return (
await Promise.all(levels.map((level) => listAllDocsByLevel(level)))
).flat();
}

async function listAllDocsByLevel(level: string) {
const docs = await _listAllDocsByLevel(level);
const flattenDocs = docs
.flatMap((doc) => {
if ("children" in doc) {
return doc.children;
}
return doc;
})
.map((doc) => {
return {
title: doc.title,
path: join(process.cwd(), "mdx", level, (doc as FileItem).relativePath),
} as { title: string; path: string; content?: string };
});
return flattenDocs;
}

export function insertOrUpdateFrontmatterKey(
docString: string,
frontmatterKey: string,
content: string,
) {
const frontmatterReg = new RegExp(`${frontmatterKey}:(.*)`);
const hasFrontmatterKey = docString.match(frontmatterReg)?.[1];

if (hasFrontmatterKey !== undefined) {
const newDocString = docString.replace(
frontmatterReg,
`${frontmatterKey}: ${content}`,
);
return newDocString;
}
const newDocString = docString.replace(
/---([\s\S]*?)---/,
`---$1${frontmatterKey}: ${content}\n---`,
);
return newDocString;
}
20 changes: 20 additions & 0 deletions scripts/open-ai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { config as envConfig } from "dotenv";
import OpenAI from "openai";
import type { ChatCompletionMessageParam } from "openai/resources/index.mjs";
envConfig({ path: ["./.env", "./.env.local"] });

const openai = new OpenAI({
apiKey: process.env.GPT_KEY,
baseURL: process.env.GPT_URL,
});

async function fetchChatCompletion(messages: ChatCompletionMessageParam[]) {
const result = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages,
});
console.log(`[chatGPT]: use ${result.usage?.total_tokens} tokens.`);
return result.choices[0].message.content;
}

export { fetchChatCompletion };

0 comments on commit 06b19f0

Please sign in to comment.