koishi-plugin-minecraft-notifier 1.6.0 → 1.7.0
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/lib/index.cjs +125 -28
- package/lib/prompt-const.d.ts +2 -1
- package/lib/translation-fetcher.d.ts +9 -1
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -63,26 +63,94 @@ function createBotTextMsgNode(bot, content) {
|
|
|
63
63
|
// src/translation-fetcher.ts
|
|
64
64
|
var import_axios = __toESM(require("axios"), 1);
|
|
65
65
|
var cheerio = __toESM(require("cheerio"), 1);
|
|
66
|
-
async function
|
|
66
|
+
async function fetchGitCodeTranslations(ctx, owner, repo, path3, token, branch = "master") {
|
|
67
|
+
try {
|
|
68
|
+
const url = `https://api.gitcode.com/api/v5/repos/${owner}/${repo}/contents/${path3}`;
|
|
69
|
+
const response = await import_axios.default.get(url, {
|
|
70
|
+
params: { ref: branch, access_token: token },
|
|
71
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
72
|
+
});
|
|
73
|
+
if (!response.data?.content) {
|
|
74
|
+
ctx.logger("translation-extractor").warn(
|
|
75
|
+
"GitCode file has no content"
|
|
76
|
+
);
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const content = Buffer.from(response.data.content, "base64").toString(
|
|
80
|
+
"utf-8"
|
|
81
|
+
);
|
|
82
|
+
return parseTranslationContent(content);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
ctx.logger("translation-extractor").warn(
|
|
85
|
+
"Failed to fetch GitCode translations:",
|
|
86
|
+
error.response?.data || error.message
|
|
87
|
+
);
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function parseTranslationContent(content) {
|
|
92
|
+
const translations = [];
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(content);
|
|
95
|
+
if (Array.isArray(parsed)) {
|
|
96
|
+
for (const item of parsed) {
|
|
97
|
+
if (item.english && item.chinese) {
|
|
98
|
+
translations.push({
|
|
99
|
+
english: item.english.trim(),
|
|
100
|
+
chinese: item.chinese.trim()
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else if (typeof parsed === "object") {
|
|
105
|
+
for (const [english, chinese] of Object.entries(parsed)) {
|
|
106
|
+
if (typeof chinese === "string") {
|
|
107
|
+
translations.push({
|
|
108
|
+
english: english.trim(),
|
|
109
|
+
chinese: chinese.trim()
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return translations;
|
|
115
|
+
} catch {
|
|
116
|
+
const lines = content.split("\n");
|
|
117
|
+
for (const line of lines) {
|
|
118
|
+
const trimmed = line.trim();
|
|
119
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("//")) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (trimmed.includes(":")) {
|
|
123
|
+
const [english, chinese] = trimmed.split(":").map((s) => s.trim());
|
|
124
|
+
if (english && chinese) {
|
|
125
|
+
translations.push({ english, chinese });
|
|
126
|
+
}
|
|
127
|
+
} else if (trimmed.includes(",")) {
|
|
128
|
+
const [english, chinese] = trimmed.split(",").map((s) => s.trim());
|
|
129
|
+
if (english && chinese) {
|
|
130
|
+
translations.push({ english, chinese });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return translations;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function fetchWikiTranslations(ctx) {
|
|
67
138
|
try {
|
|
68
139
|
const response = await import_axios.default.get(
|
|
69
140
|
"https://zh.minecraft.wiki/w/Minecraft_Wiki:%E8%AF%91%E5%90%8D%E6%A0%87%E5%87%86%E5%8C%96"
|
|
70
141
|
);
|
|
71
142
|
const html = response.data;
|
|
72
143
|
const $ = cheerio.load(html);
|
|
73
|
-
const
|
|
144
|
+
const translations = [];
|
|
74
145
|
$(".data-table").each((index, table) => {
|
|
75
146
|
const rows = $(table).find("tr");
|
|
76
|
-
let headers = null;
|
|
77
147
|
let englishCol = -1;
|
|
78
148
|
let chineseCol = -1;
|
|
79
149
|
rows.each((rowIndex, row) => {
|
|
80
150
|
const cells = $(row).find("td, th");
|
|
81
151
|
if (rowIndex === 0) {
|
|
82
|
-
headers = [];
|
|
83
152
|
cells.each((colIndex, cell) => {
|
|
84
153
|
const headerText = $(cell).text().trim();
|
|
85
|
-
headers.push(headerText);
|
|
86
154
|
if (headerText.includes("\u82F1\u6587") || headerText.includes("English")) {
|
|
87
155
|
englishCol = colIndex;
|
|
88
156
|
}
|
|
@@ -96,26 +164,62 @@ async function extractTranslations(ctx, searchStr) {
|
|
|
96
164
|
const english = $(cells[englishCol]).text().trim();
|
|
97
165
|
const chinese = $(cells[chineseCol]).text().trim();
|
|
98
166
|
if (english && chinese) {
|
|
99
|
-
|
|
100
|
-
matches.push({ english, chinese });
|
|
101
|
-
}
|
|
167
|
+
translations.push({ english, chinese });
|
|
102
168
|
}
|
|
103
169
|
}
|
|
104
170
|
});
|
|
105
171
|
});
|
|
172
|
+
return translations;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
ctx.logger("translation-extractor").warn(
|
|
175
|
+
"Failed to fetch Wiki translations:",
|
|
176
|
+
error
|
|
177
|
+
);
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function extractTranslations(ctx, cfg, searchStr) {
|
|
182
|
+
try {
|
|
183
|
+
const [wikiTranslations, gitcodeTranslations] = await Promise.all([
|
|
184
|
+
fetchWikiTranslations(ctx),
|
|
185
|
+
cfg.gitcodeApiToken && cfg.gitcodeOwner && cfg.gitcodeRepo ? fetchGitCodeTranslations(
|
|
186
|
+
ctx,
|
|
187
|
+
cfg.gitcodeOwner,
|
|
188
|
+
cfg.gitcodeRepo,
|
|
189
|
+
"Translations.json",
|
|
190
|
+
cfg.gitcodeApiToken
|
|
191
|
+
) : Promise.resolve([])
|
|
192
|
+
]);
|
|
193
|
+
const translationMap = /* @__PURE__ */ new Map();
|
|
194
|
+
for (const { english, chinese } of gitcodeTranslations) {
|
|
195
|
+
translationMap.set(english.toLowerCase(), chinese);
|
|
196
|
+
}
|
|
197
|
+
for (const { english, chinese } of wikiTranslations) {
|
|
198
|
+
translationMap.set(english.toLowerCase(), chinese);
|
|
199
|
+
}
|
|
200
|
+
const lowerSearchStr = searchStr.toLowerCase();
|
|
201
|
+
const matches = [];
|
|
202
|
+
for (const [englishLower, chinese] of translationMap.entries()) {
|
|
203
|
+
if (lowerSearchStr.includes(englishLower)) {
|
|
204
|
+
const originalEnglish = [...wikiTranslations, ...gitcodeTranslations].find(
|
|
205
|
+
(t) => t.english.toLowerCase() === englishLower
|
|
206
|
+
)?.english || englishLower;
|
|
207
|
+
matches.push({ english: originalEnglish, chinese });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
106
210
|
return matches.map(({ english, chinese }) => `${english}: ${chinese}`).join("\n");
|
|
107
211
|
} catch (error) {
|
|
108
|
-
ctx.logger("
|
|
109
|
-
"Failed to
|
|
212
|
+
ctx.logger("translation-extractor").warn(
|
|
213
|
+
"Failed to extract translations:",
|
|
110
214
|
error
|
|
111
215
|
);
|
|
112
|
-
return;
|
|
216
|
+
return "";
|
|
113
217
|
}
|
|
114
218
|
}
|
|
115
219
|
|
|
116
220
|
// src/prompt-const.ts
|
|
117
|
-
async function getSustemPrompt(ctx, searchStr) {
|
|
118
|
-
const translations = await extractTranslations(ctx, searchStr);
|
|
221
|
+
async function getSustemPrompt(ctx, cfg, searchStr) {
|
|
222
|
+
const translations = await extractTranslations(ctx, cfg, searchStr);
|
|
119
223
|
return `
|
|
120
224
|
# Role: Minecraft Update Log JSON Summarization Specialist
|
|
121
225
|
|
|
@@ -137,7 +241,7 @@ async function getSustemPrompt(ctx, searchStr) {
|
|
|
137
241
|
|
|
138
242
|
2. Localization and Format Governance
|
|
139
243
|
- Chinese Composition: Use fluent Chinese throughout, retaining necessary English proper nouns.
|
|
140
|
-
- Terminology Standards: Use community/official translations; retain English terms for internal mechanisms to prevent mistranslation
|
|
244
|
+
- Terminology Standards: Use community/official translations; retain English terms for internal mechanisms to prevent mistranslation.
|
|
141
245
|
- Emoji Selection: Choose intuitive, non-duplicated emojis for subcategories to enhance recognition and readability.
|
|
142
246
|
|
|
143
247
|
## Rules
|
|
@@ -146,7 +250,8 @@ async function getSustemPrompt(ctx, searchStr) {
|
|
|
146
250
|
- Chinese Output: Use fluent Chinese for all entries unless the English term is untranslatable proprietary nomenclature.
|
|
147
251
|
- Concise Sentences: Keep each entry under \u201Cgeneral\u201D and \u201Citems\u201D within 50-100 characters, ensuring complete and readable meaning.
|
|
148
252
|
- Accurate Categorization: Strictly map to five major categories, avoiding cross-classification or overly broad descriptions.
|
|
149
|
-
- Terminology Standards: Use standardized translations below whenever possible; e.g.,
|
|
253
|
+
- Terminology Standards: Use standardized translations below whenever possible; e.g.,
|
|
254
|
+
${translations}
|
|
150
255
|
|
|
151
256
|
2. Behavioral Guidelines:
|
|
152
257
|
- Merge Similar Updates: Consolidate duplicate or highly similar updates into a single entry, highlighting core changes.
|
|
@@ -165,7 +270,7 @@ async function getSustemPrompt(ctx, searchStr) {
|
|
|
165
270
|
- Step 1: Parse the original text, extract all changes, and preliminarily label them as new additions, optimizations, balancing, fixes, or technical changes.
|
|
166
271
|
- Step 2: Create subcategories (2-6 per category) based on thematic clustering and scope of impact; assign unique emojis to each subcategory.
|
|
167
272
|
- Step 3: Assign remaining scattered entries to general; merge and deduplicate redundant or similar content.
|
|
168
|
-
- Step 4: Perform Chinese localization and terminology proofreading; retain necessary English proper nouns. Example: Lunge \u2192 \u7A81\u8FDB;
|
|
273
|
+
- Step 4: Perform Chinese localization and terminology proofreading; retain necessary English proper nouns. Example: Lunge \u2192 \u7A81\u8FDB;
|
|
169
274
|
- Step 5: Build JSON, validating structure keys, subcategory names, Emoji uniqueness, entry length, and deduplication.
|
|
170
275
|
- Expected result: Produce structured JSON containing only five major categories, with concise Chinese entries, logical grouping, standardized spacing, unique Emojis, and readiness for group chats and publishing.
|
|
171
276
|
|
|
@@ -206,7 +311,7 @@ async function getSustemPrompt(ctx, searchStr) {
|
|
|
206
311
|
|
|
207
312
|
2. Localization and Format Governance
|
|
208
313
|
- Chinese Composition: Use fluent Chinese throughout, retaining necessary English proper nouns.
|
|
209
|
-
- Terminology Standards: Use community/official translations; retain English terms for internal mechanisms to prevent mistranslation
|
|
314
|
+
- Terminology Standards: Use community/official translations; retain English terms for internal mechanisms to prevent mistranslation.
|
|
210
315
|
- Emoji Selection: Choose intuitive, non-duplicated emojis for subcategories to enhance recognition and readability.
|
|
211
316
|
|
|
212
317
|
## Rules
|
|
@@ -234,7 +339,7 @@ async function getSustemPrompt(ctx, searchStr) {
|
|
|
234
339
|
- Step 1: Parse the original text, extract all changes, and preliminarily label them as new additions, optimizations, balancing, fixes, or technical changes.
|
|
235
340
|
- Step 2: Create subcategories (2-6 per category) based on thematic clustering and scope of impact; assign unique emojis to each subcategory.
|
|
236
341
|
- Step 3: Assign remaining scattered entries to general; merge and deduplicate redundant or similar content.
|
|
237
|
-
- Step 4: Perform Chinese localization and terminology proofreading; retain necessary English proper nouns. Example: Lunge \u2192 \u7A81\u8FDB
|
|
342
|
+
- Step 4: Perform Chinese localization and terminology proofreading; retain necessary English proper nouns. Example: Lunge \u2192 \u7A81\u8FDB;.
|
|
238
343
|
- Step 5: Build JSON, validating structure keys, subcategory names, Emoji uniqueness, entry length, and deduplication.
|
|
239
344
|
- Expected result: Produce structured JSON containing only five major categories, with concise Chinese entries, logical grouping, standardized spacing, unique Emojis, and readiness for group chats and publishing.
|
|
240
345
|
|
|
@@ -722,6 +827,7 @@ ${updateContent}
|
|
|
722
827
|
role: "system",
|
|
723
828
|
content: await getSustemPrompt(
|
|
724
829
|
ctx,
|
|
830
|
+
cfg,
|
|
725
831
|
updateContent.toLowerCase()
|
|
726
832
|
)
|
|
727
833
|
},
|
|
@@ -1039,16 +1145,7 @@ function apply(ctx, cfg) {
|
|
|
1039
1145
|
);
|
|
1040
1146
|
ctx.command("mc.trigger.gitcode", "\u624B\u52A8\u89E6\u53D1 AI \u66F4\u65B0\u65E5\u5FD7\u603B\u7ED3\u751F\u6210").action(
|
|
1041
1147
|
async () => {
|
|
1042
|
-
await
|
|
1043
|
-
ctx,
|
|
1044
|
-
cfg.gitcodeOwner,
|
|
1045
|
-
cfg.gitcodeRepo,
|
|
1046
|
-
"Custom.xaml.ini",
|
|
1047
|
-
"25w43a",
|
|
1048
|
-
`feat: update PCL HomePage XAML INI for version 25w43a`,
|
|
1049
|
-
cfg.gitcodeApiToken,
|
|
1050
|
-
"master"
|
|
1051
|
-
);
|
|
1148
|
+
return await getSustemPrompt(ctx, cfg, "jab attack");
|
|
1052
1149
|
}
|
|
1053
1150
|
);
|
|
1054
1151
|
ctx.setInterval(async () => {
|
package/lib/prompt-const.d.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
import { Context } from 'koishi';
|
|
2
|
-
|
|
2
|
+
import { Config } from './index';
|
|
3
|
+
/**
|
|
4
|
+
* 提取所有翻译(从 Wiki 和 GitCode)
|
|
5
|
+
* @param ctx - Koishi 上下文
|
|
6
|
+
* @param cfg - 配置选项
|
|
7
|
+
* @param searchStr - 搜索字符串
|
|
8
|
+
* @returns Promise<string> 格式化的翻译结果
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractTranslations(ctx: Context, cfg: Config, searchStr: string): Promise<string>;
|
package/package.json
CHANGED