グカネータ スコア補正 (#376) (#377)

Reviewed-on: #377
Co-authored-by: miteruzo <miteruzo@naver.com>
Co-committed-by: miteruzo <miteruzo@naver.com>
このコミットはPull リクエスト #377 でマージされました.
このコミットが含まれているのは:
2026-06-18 01:15:54 +09:00
committed by みてるぞ
コミット ffd28c0f9e
9個のファイルの変更1100行の追加224行の削除
+28 -16
ファイルの表示
@@ -1,15 +1,21 @@
import { expectedAnswerForQuestion } from '@/lib/gekanator'
import { isLearnedSemanticQuestion,
learnedSemanticSideForPost } from '@/lib/gekanator'
import type { GekanatorAnswerLog, GekanatorAnswerValue, GekanatorQuestion } from '@/lib/gekanator'
import type { Post } from '@/types'
export type RecoveredCandidatePost = {
postId: number
answerCountAtRecovery: number }
answerCountAtRecovery: number
scoreAtRecovery: number }
export type RecoveredCandidateState = {
answerCountAtRecovery: number
scoreAtRecovery: number }
const questionIsFactLikeForHardFiltering = (question: GekanatorQuestion): boolean =>
!(question.kind === 'post_similarity'
const questionSupportsAnswerBasedHardFiltering = (question: GekanatorQuestion): boolean =>
!(isLearnedSemanticQuestion (question)
|| (question.kind === 'tag'
&& question.condition.type === 'tag'
&& !(question.condition.key.startsWith ('nico:'))))
@@ -26,7 +32,7 @@ export const candidatePostsFor = (
answers: GekanatorAnswerLog[]
softenedQuestionIds: Set<string>
rejectedPostIds: Set<number>
recoveredCandidatePosts: Map<number, number> },
recoveredCandidatePosts: Map<number, RecoveredCandidateState> },
): Post[] => {
const questionById = new Map (questions.map (question => [question.id, question]))
@@ -34,10 +40,10 @@ export const candidatePostsFor = (
if (rejectedPostIds.has (post.id))
return false
const answerCountAtRecovery = recoveredCandidatePosts.get (post.id)
const recoveredCandidate = recoveredCandidatePosts.get (post.id)
return answers.every ((answer, index) => {
if (answerCountAtRecovery != null && index < answerCountAtRecovery)
if (recoveredCandidate != null && index < recoveredCandidate.answerCountAtRecovery)
return true
if (softenedQuestionIds.has (answer.questionId))
@@ -46,7 +52,7 @@ export const candidatePostsFor = (
const question = questionById.get (answer.questionId)
if (!(question))
return true
if (!(questionIsFactLikeForHardFiltering (question)))
if (!(questionSupportsAnswerBasedHardFiltering (question)))
return true
switch (answer.answer)
@@ -54,8 +60,10 @@ export const candidatePostsFor = (
case 'yes':
case 'no':
{
const expected = expectedAnswerForQuestion (question, post)
return expected === null || expected === 'unknown' || expected === answer.answer
const expected = learnedSemanticSideForPost (question, post)
return expected === 'unknown'
|| (answer.answer === 'yes' && expected === 'positive')
|| (answer.answer === 'no' && expected === 'negative')
}
default:
return true
@@ -70,15 +78,17 @@ export const hardFilteredPostsForAnswer = (
question: GekanatorQuestion
answer: GekanatorAnswerValue },
): Post[] => {
if (!(questionIsFactLikeForHardFiltering (question)))
if (!(questionSupportsAnswerBasedHardFiltering (question)))
return posts
if (!(answer === 'yes' || answer === 'no'))
return posts
return posts.filter (post => {
const expected = expectedAnswerForQuestion (question, post)
return expected == null || expected === 'unknown' || expected === answer
const side = learnedSemanticSideForPost (question, post)
return side === 'unknown'
|| (answer === 'yes' && side === 'positive')
|| (answer === 'no' && side === 'negative')
})
}
@@ -112,11 +122,11 @@ export const recoverCandidatePosts = (
recoveryStepCount }: { posts: Post[]
scores: Map<number, number>
rejectedPostIds: Set<number>
recoveredCandidatePosts: Map<number, number>
recoveredCandidatePosts: Map<number, RecoveredCandidateState>
eligiblePostIds: Set<number>
answerCountAtRecovery: number
recoveryStepCount: number },
): { recoveredCandidatePosts: Map<number, number>
): { recoveredCandidatePosts: Map<number, RecoveredCandidateState>
recoveryStepCount: number } | null => {
const recovered = new Map (recoveredCandidatePosts)
const targetSize = nextRecoveryTargetSize (recoveryStepCount)
@@ -140,7 +150,9 @@ export const recoverCandidatePosts = (
if (candidates.length === 0)
return null
candidates.forEach (post => recovered.set (post.id, answerCountAtRecovery))
candidates.forEach (post => recovered.set (post.id, {
answerCountAtRecovery,
scoreAtRecovery: scores.get (post.id) ?? 0 }))
return { recoveredCandidatePosts: recovered,
recoveryStepCount: recoveryStepCount + 1 }