Skip to content

Commit 9c2c770

Browse files
许君山许君山
authored andcommitted
feat: implement Gamified Conjugation Dojo mode
- Add /api/dojo-quiz endpoint to serve random verbs and conjugation questions - Add Dojo UI in App.vue with interactive quiz flow, score tracking, and feedback - Implement mode switch to toggle between Dictionary and Dojo mode - Fix port collision and update proxy to 3456
1 parent d15354a commit 9c2c770

3 files changed

Lines changed: 429 additions & 5 deletions

File tree

backend/server.js

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function lookupWordJisho(keyword) {
143143

144144
// 初始化 Ollama
145145
const app = express();
146-
const PORT = process.env.PORT || 3000;
146+
const PORT = process.env.PORT || 3456;
147147

148148
// 中间件
149149
app.use(cors({
@@ -737,6 +737,70 @@ app.get('/api/verb-types', (req, res) => {
737737
});
738738
});
739739

740+
// Dojo (动词变形道场) 题库 API
741+
app.get('/api/dojo-quiz', (req, res) => {
742+
try {
743+
const limit = parseInt(req.query.limit) || 10;
744+
if (!tokenizer) {
745+
return res.status(503).json({ error: 'Dictionary is initializing, please try again later.' });
746+
}
747+
748+
const forms = [
749+
{ key: 'negative', label: '否定式 (ない形)' },
750+
{ key: 'polite', label: '礼貌式 (ます形)' },
751+
{ key: 'teForm', label: 'て形' },
752+
{ key: 'taForm', label: '过去式 (た形)' },
753+
{ key: 'potential', label: '可能形' },
754+
{ key: 'passive', label: '被动形' },
755+
{ key: 'causative', label: '使役形' },
756+
{ key: 'imperative', label: '命令形' },
757+
{ key: 'volitional', label: '意向形' }
758+
];
759+
760+
const questions = [];
761+
const usedVerbs = new Set();
762+
763+
// 从 commonVerbs 中随机抽取
764+
while (questions.length < limit && usedVerbs.size < commonVerbs.length) {
765+
const randomIndex = Math.floor(Math.random() * commonVerbs.length);
766+
const verbObj = commonVerbs[randomIndex];
767+
768+
if (usedVerbs.has(verbObj.kanji)) continue;
769+
usedVerbs.add(verbObj.kanji);
770+
771+
// 解析动词类型
772+
const type = detectVerbType(verbObj.kana);
773+
if (!type) continue;
774+
775+
try {
776+
// 生成所有变形
777+
const result = conjugate(verbObj.kana, type);
778+
779+
// 随机挑一个考点
780+
const formObj = forms[Math.floor(Math.random() * forms.length)];
781+
const answerKana = result[formObj.key];
782+
783+
if (!answerKana) continue;
784+
785+
questions.push({
786+
verb: verbObj.kanji,
787+
kana: verbObj.kana,
788+
meaning: verbObj.meaning,
789+
formKey: formObj.key,
790+
formLabel: formObj.label,
791+
answer: answerKana
792+
});
793+
} catch (e) {
794+
// 忽略解析失败的动词
795+
}
796+
}
797+
798+
res.json(questions);
799+
} catch (error) {
800+
res.status(500).json({ error: error.message });
801+
}
802+
});
803+
740804
// 启动服务器
741805
app.listen(PORT, () => {
742806
console.log(`Japanese Verb Master API running on port ${PORT}`);

0 commit comments

Comments
 (0)