chengjie hace 4 meses
padre
commit
7cc7975c97

+ 71 - 7
src/api/yjbdc/enhanceFormsOfWords.js

@@ -38,10 +38,10 @@ function levenshteinDistance(a, b) {
38 38
 }
39 39
 
40 40
 /**
41
- * 增强FormsOfWords,检测文章中单词的变形形式和拼写错误
41
+ * 增强FormsOfWords,检测文章中单词的变形形式和拼写错误,并添加翻译
42 42
  * @param {Object} jsonObj - 解析后的JSON对象
43 43
  * @param {string} userWords - 用户提供的单词列表,逗号分隔
44
- * @returns {Object} - 增强后的JSON对象,其中FormsOfWords是字符串数组
44
+ * @returns {Object} - 增强后的JSON对象,其中FormsOfWords是英文单词数组,FormsOfWordsChinese是对应的中文翻译数组
45 45
  */
46 46
 export function enhanceFormsOfWords(jsonObj, userWords) {
47 47
     if (!jsonObj || !userWords) return jsonObj;
@@ -54,8 +54,30 @@ export function enhanceFormsOfWords(jsonObj, userWords) {
54 54
         return jsonObj;
55 55
     }
56 56
     
57
-    // 创建FormsOfWords数组,首先包含所有用户输入的单词
58
-    const formsOfWordsArray = [...userWordsList];
57
+    // 创建单词翻译映射表
58
+    const wordTranslations = {};
59
+    
60
+    // 处理WordChinese字段,提取单词翻译
61
+    if (jsonObj.WordChinese && Array.isArray(jsonObj.WordChinese)) {
62
+        jsonObj.WordChinese.forEach(item => {
63
+            const parts = item.split(':');
64
+            if (parts.length >= 2) {
65
+                const word = parts[0].trim().toLowerCase();
66
+                const translation = parts.slice(1).join(':').trim();
67
+                wordTranslations[word] = translation;
68
+            }
69
+        });
70
+    }
71
+    
72
+    // 创建FormsOfWords数组和FormsOfWordsChinese数组
73
+    const formsOfWordsArray = [];
74
+    const formsOfWordsChineseArray = [];
75
+    
76
+    // 首先添加用户输入的单词
77
+    userWordsList.forEach(word => {
78
+        formsOfWordsArray.push(word);
79
+        formsOfWordsChineseArray.push(wordTranslations[word] || "");
80
+    });
59 81
     
60 82
     // 存储原始句子和小写句子的映射,用于保留大小写
61 83
     const originalSentences = {};
@@ -349,16 +371,58 @@ export function enhanceFormsOfWords(jsonObj, userWords) {
349 371
             }
350 372
         });
351 373
         
352
-        // 将找到的匹配形式添加到结果数组中
374
+        // 将找到的匹配形式添加到结果数组中,并添加翻译
353 375
         matchedForms.forEach(form => {
354
-            if (!formsOfWordsArray.includes(form)) {
376
+            // 检查是否已经存在于结果数组中
377
+            const formLower = form.toLowerCase();
378
+            const existingIndex = formsOfWordsArray.findIndex(item => 
379
+                item.toLowerCase() === formLower
380
+            );
381
+            
382
+            if (existingIndex === -1) {
383
+                // 查找原始单词的翻译
384
+                let translation = null;
385
+                
386
+                // 检查不规则动词的特殊情况
387
+                const irregularVerbs = {
388
+                    'be': ['am', 'is', 'are', 'was', 'were', 'been', 'being'],
389
+                    // 其他不规则动词...
390
+                };
391
+                
392
+                // 查找这个单词是否是某个不规则动词的变形
393
+                for (const [baseWord, forms] of Object.entries(irregularVerbs)) {
394
+                    if (forms.includes(formLower) && wordTranslations[baseWord]) {
395
+                        translation = wordTranslations[baseWord];
396
+                        break;
397
+                    }
398
+                }
399
+                
400
+                // 如果没有找到特殊情况的翻译,尝试查找原始单词的翻译
401
+                if (!translation) {
402
+                    for (const originalWord of userWordsList) {
403
+                        if (checkSpecialWordForms(formLower, originalWord) || 
404
+                            checkSpecialWordForms(originalWord, formLower)) {
405
+                            translation = wordTranslations[originalWord];
406
+                            if (translation) break;
407
+                        }
408
+                    }
409
+                }
410
+                
411
+                // 添加单词和对应的翻译到各自的数组
355 412
                 formsOfWordsArray.push(form);
413
+                formsOfWordsChineseArray.push(translation || "");
356 414
             }
357 415
         });
358 416
     });
359 417
     
360
-    // 将结果数组赋值给jsonObj.FormsOfWords
418
+    // 将结果数组赋值给jsonObj的相应字段
361 419
     jsonObj.FormsOfWords = formsOfWordsArray;
420
+    jsonObj.FormsOfWordsChinese = formsOfWordsChineseArray;
421
+    
422
+    // 删除 WordChinese 字段,因为已经将翻译整合到 FormsOfWordsChinese 中
423
+    if (jsonObj.WordChinese) {
424
+        delete jsonObj.WordChinese;
425
+    }
362 426
     
363 427
     return jsonObj;
364 428
 }

+ 3 - 0
src/api/yjbdc/routes.js

@@ -15,6 +15,9 @@ router.get('/api/BuildYJBDCQRCode',yjbdcController.BuildYJBDCQRCode);
15 15
 router.get('/api/DeleteYJBDCArticleList',yjbdcController.DeleteYJBDCArticleList);
16 16
 router.get('/api/UpdateYJBDCArticleReadCount',yjbdcController.UpdateYJBDCArticleReadCount);
17 17
 router.get('/api/GetMiaoguoTodayAllWords',yjbdcController.GetMiaoguoTodayAllWords);
18
+router.get('/api/GetWordChinese',yjbdcController.GetWordChinese);
19
+
18 20
 router.get('/yjbdc_article_admin',yjbdcController.YJBDC_Articles_Admin);
19 21
 
22
+
20 23
 export default router;

+ 101 - 1
src/api/yjbdc/yjbdcController.js

@@ -218,11 +218,13 @@ export async function GenerateArticle(ctx) {
218 218
                     "每句分数组提供中英双语,ArticleEnglish必须纯英文不含中文,ArticleChinese必须纯中文不含未翻译的英文单词",
219 219
                     "所有单词至少出现一次(允许变形)",
220 220
                     "生成5道四选一阅读题(含答案)",
221
+                    "提供用户单词在文中中文翻译",
221 222
                     "所有字段必须完整出现,任何缺失需立即补全并维持原顺序,特别是Question中的所有字段(QuestionEnglish、QuestionChinese、OptionsEnglish、OptionsChinese、Answer)都必须存在"
222 223
                 ],
223 224
                 "output_format": {
224 225
                     "ArticleEnglish": ["句子1", "句子2..."],
225 226
                     "ArticleChinese": ["翻译1", "翻译2..."],
227
+                    "WordChinese": ["单词1:翻译1", "单词2:翻译2..."],
226 228
                     "Question": [{
227 229
                     "QuestionEnglish": "题干",
228 230
                     "QuestionChinese": "题干翻译",
@@ -390,7 +392,7 @@ export async function GetYJBDCGenerateConfig(ctx) {
390 392
     ctx.body = {"errcode": 10000, result:result};
391 393
 }
392 394
 
393
-//获得秒过当天任务完成后的英语单词(未完成)
395
+//获得秒过当天任务完成后的英语单词
394 396
 export async function GetMiaoguoTodayAllWords(ctx) {
395 397
     const param = {
396 398
         UserID: ctx.query.UserID || 0,
@@ -1243,6 +1245,104 @@ export async function BuildYJBDCQRCode(ctx) {
1243 1245
     }
1244 1246
 }
1245 1247
 
1248
+export async function GetWordChinese(ctx) {
1249
+    const param = {
1250
+        UserID: ctx.query.UserID || 0,
1251
+        Word: ctx.query.Word || '',
1252
+        Level: ctx.query.Level || '0'
1253
+    };
1254
+    
1255
+    if (!param.Word) {
1256
+        ctx.body = {"errcode": 10001, "errStr": "单词不能为空"};
1257
+        return;
1258
+    }
1259
+    
1260
+    // 使用单词作为缓存键,为每个单词单独缓存结果
1261
+    const cacheKey = `GetWordChinese_${param.Word}_${param.Level}`;
1262
+    let result = globalCache.get(cacheKey);
1263
+    
1264
+    if (!result) {
1265
+        // 缓存未命中,从数据库获取
1266
+        result = await yjbdc.GetWordChinese(param);
1267
+        
1268
+        // 如果没有找到结果,尝试查找单词的原形
1269
+        if (!result || result.length === 0) {
1270
+            // 使用stringUtils.getWordBaseForm获取可能的原形
1271
+            const possibleBaseWords = stringUtils.getWordBaseForm(param.Word);
1272
+            
1273
+            // 尝试每个可能的原形
1274
+            for (const baseWord of possibleBaseWords) {
1275
+                console.log(`尝试查找单词 ${param.Word} 的可能原形: ${baseWord}`);
1276
+                const baseParam = {...param, Word: baseWord};
1277
+                const baseResult = await yjbdc.GetWordChinese(baseParam);
1278
+                
1279
+                if (baseResult && baseResult.length > 0) {
1280
+                    console.log(`找到单词 ${param.Word} 的原形 ${baseWord}`);
1281
+                    result = baseResult;
1282
+                    break;
1283
+                }
1284
+            }
1285
+        }
1286
+        
1287
+        // 缓存结果,使用较长的过期时间,因为单词释义很少变化
1288
+        if (result && result.length > 0) {
1289
+            globalCache.set(cacheKey, result, config.BufferMemoryTimeHighBest);
1290
+            console.log(`缓存单词 ${param.Word} 的释义,7天有效期`);
1291
+        }
1292
+    }
1293
+
1294
+    // 根据Level筛选合适的单词释义
1295
+    let selectedResult = null;
1296
+    if (result && result.length > 0) {
1297
+        // 将Level转换为数字
1298
+        const level = parseInt(param.Level);
1299
+        
1300
+        // 根据不同Level筛选结果
1301
+        if (level >= 0 && level <= 2) {
1302
+            // Level 0-2,返回数组单词第一条
1303
+            selectedResult = result[0];
1304
+        } else if (level === 3) {
1305
+            // Level 3,优选返回BookID >= 169的
1306
+            const filtered = result.filter(item => item.BookID >= 169);
1307
+            if (filtered.length > 0) {
1308
+                selectedResult = filtered[0];
1309
+            } else {
1310
+                // 如果没有符合条件的,返回BookID较大的第一条
1311
+                result.sort((a, b) => b.BookID - a.BookID);
1312
+                selectedResult = result[0];
1313
+            }
1314
+        } else if (level === 4) {
1315
+            // Level 4,优选返回BookID >= 173的
1316
+            const filtered = result.filter(item => item.BookID >= 173);
1317
+            if (filtered.length > 0) {
1318
+                selectedResult = filtered[0];
1319
+            } else {
1320
+                // 如果没有符合条件的,返回BookID较大的第一条
1321
+                result.sort((a, b) => b.BookID - a.BookID);
1322
+                selectedResult = result[0];
1323
+            }
1324
+        } else if (level === 5) {
1325
+            // Level 5,优选返回BookID >= 178的
1326
+            const filtered = result.filter(item => item.BookID >= 178);
1327
+            if (filtered.length > 0) {
1328
+                selectedResult = filtered[0];
1329
+            } else {
1330
+                // 如果没有符合条件的,返回BookID较大的第一条
1331
+                result.sort((a, b) => b.BookID - a.BookID);
1332
+                selectedResult = result[0];
1333
+            }
1334
+        }
1335
+        
1336
+        // 移除 BookID 字段
1337
+        if (selectedResult) {
1338
+            delete selectedResult.BookID;
1339
+        }
1340
+    }
1341
+
1342
+    ctx.body = {"errcode": 10000, result: selectedResult};
1343
+}
1344
+
1345
+
1246 1346
 export async function YJBDC_Articles_Admin(ctx) {
1247 1347
     console.log("yjbdc_articles");
1248 1348
     const data = await fsPromises.readFile("./public/mg/yjbdc_articles.html");

+ 11 - 0
src/model/yjbdc.js

@@ -151,6 +151,17 @@ class YJBDC {
151 151
         }
152 152
     }
153 153
 
154
+    static async GetWordChinese(obj) {
155
+        try {
156
+            // 直接在数据库层面过滤出特定单词,获取包含BookID的数据
157
+            const sql = "SELECT Word, Translate, BookID FROM kylx365_db.Words w WHERE w.Word = ? AND ((w.BookID>=151 AND w.BookID<=153) OR (w.BookID>=169 AND w.BookID<=183)) ORDER BY w.BookID;";
158
+            return await query(sql, [obj.Word]);
159
+        } catch (error) {
160
+            console.error('获取单词信息失败:', error);
161
+            throw error;
162
+        }
163
+    }
164
+
154 165
 
155 166
 }
156 167
 

+ 120 - 0
src/util/stringClass.js

@@ -67,6 +67,35 @@ import os from 'os';
67 67
  * @property {Function} cleanWord - 清理单词中的非字母字符
68 68
  * @property {Function} extractEnglishWords - 从文本中提取英语单词
69 69
  */
70
+// 不规则动词映射
71
+const irregularVerbs = {
72
+    'go': ['went', 'gone', 'going', 'goes'],
73
+    'be': ['am', 'is', 'are', 'was', 'were', 'been', 'being'],
74
+    'do': ['did', 'done', 'doing', 'does'],
75
+    'have': ['has', 'had', 'having'],
76
+    'say': ['said', 'saying', 'says'],
77
+    'make': ['made', 'making', 'makes'],
78
+    'get': ['got', 'gotten', 'getting', 'gets'],
79
+    'know': ['knew', 'known', 'knowing', 'knows'],
80
+    'take': ['took', 'taken', 'taking', 'takes'],
81
+    'see': ['saw', 'seen', 'seeing', 'sees'],
82
+    'come': ['came', 'coming', 'comes'],
83
+    'think': ['thought', 'thinking', 'thinks'],
84
+    'look': ['looked', 'looking', 'looks'],
85
+    'want': ['wanted', 'wanting', 'wants'],
86
+    'give': ['gave', 'given', 'giving', 'gives'],
87
+    'use': ['used', 'using', 'uses'],
88
+    'find': ['found', 'finding', 'finds'],
89
+    'tell': ['told', 'telling', 'tells'],
90
+    'ask': ['asked', 'asking', 'asks'],
91
+    'work': ['worked', 'working', 'works'],
92
+    'seem': ['seemed', 'seeming', 'seems'],
93
+    'feel': ['felt', 'feeling', 'feels'],
94
+    'try': ['tried', 'trying', 'tries'],
95
+    'leave': ['left', 'leaving', 'leaves'],
96
+    'call': ['called', 'calling', 'calls']
97
+};
98
+
70 99
 export const stringUtils = {
71 100
     //给字符串左侧补零
72 101
     AddZero: (str, length) => {
@@ -725,4 +754,95 @@ export const stringUtils = {
725 754
         //console.groupEnd();
726 755
         return result;
727 756
     },
757
+    
758
+    /**
759
+     * 获取单词的原形(基本形式)
760
+     * @param {string} word - 要转换的单词
761
+     * @returns {string[]} - 可能的原形单词数组
762
+     */
763
+    getWordBaseForm: (word) => {
764
+        const lowerWord = word.toLowerCase();
765
+        const possibleBaseWords = [];
766
+        
767
+        // 检查是否是不规则动词的变形
768
+        for (const [base, forms] of Object.entries(irregularVerbs)) {
769
+            if (forms.includes(lowerWord)) {
770
+                possibleBaseWords.push(base);
771
+                return possibleBaseWords; // 不规则动词直接返回原形
772
+            }
773
+        }
774
+        
775
+        // 处理规则变形
776
+        
777
+        // 处理过去式/过去分词 (-ed)
778
+        if (lowerWord.endsWith('ed')) {
779
+            possibleBaseWords.push(lowerWord.slice(0, -2)); // 常规情况 (walked -> walk)
780
+        }
781
+        
782
+        // 处理以e结尾的动词加d的情况
783
+        if (lowerWord.endsWith('d') && !lowerWord.endsWith('ed')) {
784
+            possibleBaseWords.push(lowerWord.slice(0, -1)); // 如 used -> use
785
+        }
786
+        
787
+        // 处理以辅音+y结尾变为ied的情况
788
+        if (lowerWord.endsWith('ied')) {
789
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'y'); // 如 tried -> try
790
+        }
791
+        
792
+        // 处理现在分词 (-ing)
793
+        if (lowerWord.endsWith('ing')) {
794
+            possibleBaseWords.push(lowerWord.slice(0, -3)); // 常规情况 (walking -> walk)
795
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'e'); // 以e结尾的动词 (making -> make)
796
+        }
797
+        
798
+        // 处理比较级/最高级
799
+        if (lowerWord.endsWith('er')) {
800
+            possibleBaseWords.push(lowerWord.slice(0, -2)); // 常规情况 (faster -> fast)
801
+        }
802
+        if (lowerWord.endsWith('est')) {
803
+            possibleBaseWords.push(lowerWord.slice(0, -3)); // 常规情况 (fastest -> fast)
804
+        }
805
+        
806
+        // 处理以辅音+y结尾变为ier/iest的情况
807
+        if (lowerWord.endsWith('ier')) {
808
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'y'); // 如 happier -> happy
809
+        }
810
+        if (lowerWord.endsWith('iest')) {
811
+            possibleBaseWords.push(lowerWord.slice(0, -4) + 'y'); // 如 happiest -> happy
812
+        }
813
+        
814
+        // 处理副词 (-ly)
815
+        if (lowerWord.endsWith('ly')) {
816
+            possibleBaseWords.push(lowerWord.slice(0, -2)); // 常规情况 (quickly -> quick)
817
+        }
818
+        
819
+        // 处理以y结尾变为ily的情况
820
+        if (lowerWord.endsWith('ily')) {
821
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'y'); // 如 happily -> happy
822
+        }
823
+        
824
+        // 处理复数形式
825
+        if (lowerWord.endsWith('s') && !lowerWord.endsWith('ss')) {
826
+            possibleBaseWords.push(lowerWord.slice(0, -1)); // 常规情况 (books -> book)
827
+        }
828
+        if (lowerWord.endsWith('es')) {
829
+            possibleBaseWords.push(lowerWord.slice(0, -2)); // 常规情况 (boxes -> box)
830
+        }
831
+        
832
+        // 处理以y结尾变为ies的情况
833
+        if (lowerWord.endsWith('ies')) {
834
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'y'); // 如 cities -> city
835
+        }
836
+        
837
+        // 处理以fe结尾变为ves的情况
838
+        if (lowerWord.endsWith('ves')) {
839
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'fe'); // 如 knives -> knife
840
+            possibleBaseWords.push(lowerWord.slice(0, -3) + 'f'); // 如 leaves -> leaf
841
+        }
842
+        
843
+        // 去重并过滤掉过短的单词
844
+        const uniqueBaseWords = [...new Set(possibleBaseWords)].filter(w => w.length >= 2);
845
+        
846
+        return uniqueBaseWords;
847
+    },
728 848
 }