milestone 9
This commit is contained in:
@@ -178,8 +178,26 @@ export async function startLearningSession(
|
||||
}
|
||||
}
|
||||
|
||||
const newHanzi = await prisma.hanzi.findMany({
|
||||
// First, get all available new hanzi IDs (lightweight query)
|
||||
const availableNewHanzi = await prisma.hanzi.findMany({
|
||||
where: newHanziWhereClause,
|
||||
select: { id: true },
|
||||
})
|
||||
|
||||
// Randomly select N hanzi IDs from all available
|
||||
// Fisher-Yates shuffle
|
||||
const shuffledIds = [...availableNewHanzi]
|
||||
for (let i = shuffledIds.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
;[shuffledIds[i], shuffledIds[j]] = [shuffledIds[j], shuffledIds[i]]
|
||||
}
|
||||
const selectedNewHanziIds = shuffledIds.slice(0, neededCards).map(h => h.id)
|
||||
|
||||
// Now fetch full details for the randomly selected hanzi
|
||||
const newHanzi = await prisma.hanzi.findMany({
|
||||
where: {
|
||||
id: { in: selectedNewHanziIds },
|
||||
},
|
||||
include: {
|
||||
forms: {
|
||||
where: { isDefault: true },
|
||||
@@ -191,7 +209,6 @@ export async function startLearningSession(
|
||||
},
|
||||
hskLevels: true,
|
||||
},
|
||||
take: neededCards,
|
||||
})
|
||||
|
||||
// Create initial progress for new cards
|
||||
@@ -223,6 +240,13 @@ export async function startLearningSession(
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle final card set (in case new cards were added after initial shuffle)
|
||||
// Fisher-Yates shuffle
|
||||
for (let i = selectedCards.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
;[selectedCards[i], selectedCards[j]] = [selectedCards[j], selectedCards[i]]
|
||||
}
|
||||
|
||||
// Create learning session
|
||||
const learningSession = await prisma.learningSession.create({
|
||||
data: {
|
||||
@@ -262,12 +286,14 @@ export async function startLearningSession(
|
||||
if (!pinyinTranscription) continue
|
||||
|
||||
const correctPinyin = pinyinTranscription.value
|
||||
const characterCount = hanzi.simplified.length
|
||||
|
||||
// Get HSK level for this hanzi
|
||||
const hskLevel = hanzi.hskLevels[0]?.level || "new-1"
|
||||
|
||||
// Get other hanzi from same HSK level for wrong answers
|
||||
const sameHskHanzi = await prisma.hanzi.findMany({
|
||||
// Get ALL available hanzi IDs from same HSK level (lightweight query)
|
||||
// This prevents always fetching the same alphabetically-first hanzi
|
||||
const allSameHskIds = await prisma.hanzi.findMany({
|
||||
where: {
|
||||
id: { not: hanzi.id },
|
||||
hskLevels: {
|
||||
@@ -276,6 +302,32 @@ export async function startLearningSession(
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
simplified: true, // Need this for character count filtering
|
||||
},
|
||||
})
|
||||
|
||||
// Filter to same character count
|
||||
const sameCharCountIds = allSameHskIds.filter(
|
||||
h => h.simplified.length === characterCount
|
||||
)
|
||||
|
||||
// Shuffle ALL matching IDs
|
||||
const shuffledIds = [...sameCharCountIds]
|
||||
for (let i = shuffledIds.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
;[shuffledIds[i], shuffledIds[j]] = [shuffledIds[j], shuffledIds[i]]
|
||||
}
|
||||
|
||||
// Take first 50 from shuffled (or all if less than 50)
|
||||
const selectedIds = shuffledIds.slice(0, 50).map(h => h.id)
|
||||
|
||||
// Fetch full details for selected IDs
|
||||
let candidatesForWrongAnswers = await prisma.hanzi.findMany({
|
||||
where: {
|
||||
id: { in: selectedIds },
|
||||
},
|
||||
include: {
|
||||
forms: {
|
||||
where: { isDefault: true },
|
||||
@@ -286,11 +338,57 @@ export async function startLearningSession(
|
||||
},
|
||||
},
|
||||
},
|
||||
take: 10, // Get extra to ensure enough unique options
|
||||
})
|
||||
|
||||
// If not enough candidates, get more from any HSK level with same character count
|
||||
if (candidatesForWrongAnswers.length < 10) {
|
||||
const additionalAllIds = await prisma.hanzi.findMany({
|
||||
where: {
|
||||
id: {
|
||||
not: hanzi.id,
|
||||
notIn: candidatesForWrongAnswers.map(h => h.id),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
simplified: true,
|
||||
},
|
||||
})
|
||||
|
||||
const additionalSameCharIds = additionalAllIds.filter(
|
||||
h => h.simplified.length === characterCount
|
||||
)
|
||||
|
||||
// Shuffle additional IDs
|
||||
const shuffledAdditional = [...additionalSameCharIds]
|
||||
for (let i = shuffledAdditional.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
;[shuffledAdditional[i], shuffledAdditional[j]] = [shuffledAdditional[j], shuffledAdditional[i]]
|
||||
}
|
||||
|
||||
const additionalSelectedIds = shuffledAdditional.slice(0, 30).map(h => h.id)
|
||||
|
||||
const additionalHanzi = await prisma.hanzi.findMany({
|
||||
where: {
|
||||
id: { in: additionalSelectedIds },
|
||||
},
|
||||
include: {
|
||||
forms: {
|
||||
where: { isDefault: true },
|
||||
include: {
|
||||
transcriptions: {
|
||||
where: { type: "pinyin" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
candidatesForWrongAnswers = [...candidatesForWrongAnswers, ...additionalHanzi]
|
||||
}
|
||||
|
||||
// Convert to HanziOption format
|
||||
const hanziOptions: HanziOption[] = sameHskHanzi
|
||||
const hanziOptions: HanziOption[] = candidatesForWrongAnswers
|
||||
.map(h => {
|
||||
const form = h.forms[0]
|
||||
const pinyin = form?.transcriptions[0]
|
||||
|
||||
Reference in New Issue
Block a user