hexo-theme-shokax 0.4.21 → 0.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_config.yml +12 -12
- package/package.json +2 -1
- package/scripts/generaters/summary_ai.js +115 -0
- package/scripts/helpers/summary_ai.js +1 -108
package/_config.yml
CHANGED
@@ -203,12 +203,12 @@ waline:
|
|
203
203
|
lang: "zh-CN"
|
204
204
|
locale: {} # https://waline.js.org/guide/features/i18n.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AF%AD%E8%A8%80
|
205
205
|
emoji: # 表情包
|
206
|
-
- https://unpkg.com/@waline/emojis@1.0.1/weibo
|
207
|
-
- https://unpkg.com/@waline/emojis@1.0.1/alus
|
208
|
-
- https://unpkg.com/@waline/emojis@1.0.1/bilibili
|
209
|
-
- https://unpkg.com/@waline/emojis@1.0.1/qq
|
210
|
-
- https://unpkg.com/@waline/emojis@1.0.1/tieba
|
211
|
-
- https://unpkg.com/@waline/emojis@1.0.1/tw-emoji
|
206
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/weibo
|
207
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/alus
|
208
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/bilibili
|
209
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/qq
|
210
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/tieba
|
211
|
+
# - https://unpkg.com/@waline/emojis@1.0.1/tw-emoji
|
212
212
|
meta: # 可以填写的内容
|
213
213
|
- nick
|
214
214
|
- mail
|
@@ -222,12 +222,12 @@ waline:
|
|
222
222
|
|
223
223
|
summary:
|
224
224
|
enable: false
|
225
|
-
introduce: "
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
225
|
+
introduce: "" # AI自我介绍
|
226
|
+
model:
|
227
|
+
apiKey:
|
228
|
+
apiUrl:
|
229
|
+
temperature:
|
230
|
+
initalPrompt:
|
231
231
|
|
232
232
|
# Social Links
|
233
233
|
# Usage: `Key: permalink || icon || color`
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "hexo-theme-shokax",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.22",
|
4
4
|
"description": "a hexo theme based on shoka",
|
5
5
|
"main": "index.js",
|
6
6
|
"repository": "https://github.com/theme-shoka-x/hexo-theme-shokaX",
|
@@ -31,6 +31,7 @@
|
|
31
31
|
"@waline/client": "^3.5.2",
|
32
32
|
"algoliasearch": "5.20.3",
|
33
33
|
"dompurify": "^3.2.4",
|
34
|
+
"es-toolkit": "^1.32.0",
|
34
35
|
"esbuild": "^0.25.0",
|
35
36
|
"hexo": "^7.3.0",
|
36
37
|
"hexo-algoliasearch": "^2.0.1",
|
@@ -0,0 +1,115 @@
|
|
1
|
+
var __create = Object.create;
|
2
|
+
var __defProp = Object.defineProperty;
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
7
|
+
var __copyProps = (to, from, except, desc) => {
|
8
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
9
|
+
for (let key of __getOwnPropNames(from))
|
10
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
11
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
12
|
+
}
|
13
|
+
return to;
|
14
|
+
};
|
15
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
16
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
17
|
+
// file that has been converted to a CommonJS file using a Babel-
|
18
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
19
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
20
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
21
|
+
mod
|
22
|
+
));
|
23
|
+
var import_node_crypto = require("node:crypto");
|
24
|
+
var import_promises = __toESM(require("node:fs/promises"));
|
25
|
+
async function getSummaryByAPI(content) {
|
26
|
+
const config = hexo.theme.config.summary;
|
27
|
+
const apiKey = config.apiKey;
|
28
|
+
const apiUrl = config.apiUrl;
|
29
|
+
const model = config.model;
|
30
|
+
const temperature = config.temperature ?? 1.3;
|
31
|
+
const initalPrompt = config.initalPrompt;
|
32
|
+
const res = await fetch(apiUrl, {
|
33
|
+
method: "POST",
|
34
|
+
headers: {
|
35
|
+
"Content-Type": "application/json",
|
36
|
+
"Authorization": `Bearer ${apiKey}`
|
37
|
+
},
|
38
|
+
body: JSON.stringify({
|
39
|
+
model,
|
40
|
+
messages: [{ role: "user", content: `${initalPrompt} ${content}` }],
|
41
|
+
temperature
|
42
|
+
})
|
43
|
+
});
|
44
|
+
if (!res.ok) {
|
45
|
+
throw new Error(`Error: ${res.status} ${res.statusText}`);
|
46
|
+
}
|
47
|
+
const data = await res.json();
|
48
|
+
if (data.error) {
|
49
|
+
throw new Error(`Error: ${data.error.message}`);
|
50
|
+
}
|
51
|
+
const summary = data.choices[0].message.content;
|
52
|
+
return summary;
|
53
|
+
}
|
54
|
+
class SummaryDatabase {
|
55
|
+
fileChanged;
|
56
|
+
data;
|
57
|
+
constructor() {
|
58
|
+
this.fileChanged = false;
|
59
|
+
this.data = {
|
60
|
+
version: 2,
|
61
|
+
features: {
|
62
|
+
incremental: false
|
63
|
+
},
|
64
|
+
summaries: {}
|
65
|
+
};
|
66
|
+
}
|
67
|
+
async readDB() {
|
68
|
+
try {
|
69
|
+
await import_promises.default.access("summary.json");
|
70
|
+
this.data = JSON.parse(await import_promises.default.readFile("summary.json", "utf-8"));
|
71
|
+
} catch (error) {
|
72
|
+
}
|
73
|
+
if (this.data.version !== 2) {
|
74
|
+
throw new Error(`Incompatible version of summary database: ${this.data.version}`);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
async writeDB() {
|
78
|
+
if (this.fileChanged) {
|
79
|
+
await import_promises.default.writeFile("summary.json", JSON.stringify(this.data));
|
80
|
+
}
|
81
|
+
}
|
82
|
+
async getPostSummary(path, content) {
|
83
|
+
const pathHash = (0, import_node_crypto.createHash)("sha256").update(path).digest("hex");
|
84
|
+
const contentHash = (0, import_node_crypto.createHash)("sha256").update(content).digest("hex");
|
85
|
+
if (this.data.summaries[pathHash]?.sha256 === contentHash) {
|
86
|
+
return this.data.summaries[pathHash].summary;
|
87
|
+
} else {
|
88
|
+
const summaryContent = await getSummaryByAPI(content);
|
89
|
+
this.data.summaries[pathHash] = {
|
90
|
+
summary: summaryContent,
|
91
|
+
sha256: contentHash
|
92
|
+
};
|
93
|
+
this.fileChanged = true;
|
94
|
+
return summaryContent;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
hexo.extend.generator.register("summary_ai", async function(locals) {
|
99
|
+
const posts = locals.posts;
|
100
|
+
if (!hexo.theme.config.summary.enable) {
|
101
|
+
return;
|
102
|
+
}
|
103
|
+
const db = new SummaryDatabase();
|
104
|
+
await db.readDB();
|
105
|
+
for (const post of posts.toArray()) {
|
106
|
+
const content = post.content;
|
107
|
+
const path = post.path;
|
108
|
+
const published = post.published;
|
109
|
+
if (content && path && published && content.length > 0) {
|
110
|
+
const summary = await db.getPostSummary(path, content);
|
111
|
+
post.summary = summary;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
await db.writeDB();
|
115
|
+
});
|
@@ -1,112 +1,5 @@
|
|
1
|
-
var __create = Object.create;
|
2
|
-
var __defProp = Object.defineProperty;
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
7
|
-
var __copyProps = (to, from, except, desc) => {
|
8
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
9
|
-
for (let key of __getOwnPropNames(from))
|
10
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
11
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
12
|
-
}
|
13
|
-
return to;
|
14
|
-
};
|
15
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
16
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
17
|
-
// file that has been converted to a CommonJS file using a Babel-
|
18
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
19
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
20
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
21
|
-
mod
|
22
|
-
));
|
23
|
-
var import_node_fs = __toESM(require("node:fs"));
|
24
|
-
function getContent(post) {
|
25
|
-
return post?.raw ?? post?._content ?? post.content;
|
26
|
-
}
|
27
|
-
let db;
|
28
|
-
function postMessage(path, content, dbPath, startMessage) {
|
29
|
-
if (import_node_fs.default.existsSync("summary.json")) {
|
30
|
-
db = JSON.parse(import_node_fs.default.readFileSync("summary.json", { encoding: "utf-8" }));
|
31
|
-
} else {
|
32
|
-
db = {};
|
33
|
-
}
|
34
|
-
const config = hexo.theme.config.summary;
|
35
|
-
if (config.enable) {
|
36
|
-
if (typeof db?.[path] !== "undefined" && typeof db?.[path]?.[dbPath] !== "undefined") {
|
37
|
-
return db[path][dbPath];
|
38
|
-
} else {
|
39
|
-
if (typeof db?.[path] === "undefined") {
|
40
|
-
db[path] = {};
|
41
|
-
} else {
|
42
|
-
db[path][dbPath] = "";
|
43
|
-
}
|
44
|
-
}
|
45
|
-
if (config.mode === "openai") {
|
46
|
-
const request = () => {
|
47
|
-
fetch(`${config.openai.remote}/v1/chat/completions`, {
|
48
|
-
method: "POST",
|
49
|
-
headers: requestHeaders,
|
50
|
-
body: JSON.stringify(requestBody)
|
51
|
-
}).then((response) => {
|
52
|
-
if (!response.ok) {
|
53
|
-
throw Error("ERROR: Failed to get summary from Openai API");
|
54
|
-
}
|
55
|
-
response.json().then((data) => {
|
56
|
-
const summary = data.choices[0].message.content;
|
57
|
-
try {
|
58
|
-
db[path][dbPath] = summary;
|
59
|
-
} catch (e) {
|
60
|
-
db ??= {};
|
61
|
-
db[path] ??= {};
|
62
|
-
db[path][dbPath] ??= "";
|
63
|
-
db[path][dbPath] = summary;
|
64
|
-
}
|
65
|
-
import_node_fs.default.writeFileSync("summary.json", JSON.stringify(db));
|
66
|
-
if (import_node_fs.default.existsSync("requested.lock")) {
|
67
|
-
import_node_fs.default.unlinkSync("requested.lock");
|
68
|
-
}
|
69
|
-
return summary;
|
70
|
-
});
|
71
|
-
});
|
72
|
-
};
|
73
|
-
const checkTime = (waitTime) => {
|
74
|
-
if (import_node_fs.default.existsSync("request.lock")) {
|
75
|
-
if (import_node_fs.default.existsSync("requested.lock")) {
|
76
|
-
setTimeout(checkTime, 1e3 * waitTime);
|
77
|
-
return;
|
78
|
-
}
|
79
|
-
import_node_fs.default.writeFileSync("requested.lock", "");
|
80
|
-
setTimeout(request, 1e3 * 2.5 * waitTime);
|
81
|
-
import_node_fs.default.unlinkSync("request.lock");
|
82
|
-
} else {
|
83
|
-
import_node_fs.default.writeFileSync("request.lock", "");
|
84
|
-
request();
|
85
|
-
}
|
86
|
-
};
|
87
|
-
const requestHeaders = {
|
88
|
-
"Content-Type": "application/json",
|
89
|
-
Authorization: `Bearer ${config.openai.apikey}`
|
90
|
-
};
|
91
|
-
const requestBody = {
|
92
|
-
model: "gpt-3.5-turbo",
|
93
|
-
messages: [{ role: "user", content: `${startMessage} ${content}` }],
|
94
|
-
temperature: 0.7
|
95
|
-
};
|
96
|
-
if (config.pricing === "trial") {
|
97
|
-
hexo.log.info("Requesting OpenAI API... (3 RPM mode)");
|
98
|
-
hexo.log.info("It may take 20 minutes or more (depending on the number of articles, each one takes 25 seconds)");
|
99
|
-
checkTime(10);
|
100
|
-
} else {
|
101
|
-
hexo.log.info("Requesting OpenAI API... (60 RPM mode)");
|
102
|
-
checkTime(0.5);
|
103
|
-
}
|
104
|
-
} else {
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
1
|
hexo.extend.helper.register("get_summary", (post) => {
|
109
|
-
return
|
2
|
+
return post.summary;
|
110
3
|
});
|
111
4
|
hexo.extend.helper.register("get_introduce", () => {
|
112
5
|
return hexo.theme.config.summary.introduce;
|