このコミットが含まれているのは:
2026-06-18 00:59:48 +09:00
コミット 3f1c6c135b
7個のファイルの変更987行の追加224行の削除
+50 -7
ファイルの表示
@@ -9,11 +9,24 @@ export type GekanatorAnswerValue =
| 'probably_no'
| 'unknown'
export type LearnedSemanticSide =
| 'positive'
| 'negative'
| 'unknown'
export type GekanatorQuestionPurpose =
| 'effective_user_suggested'
| 'learning_user_suggested'
| 'normal'
export type GekanatorAnswerLog = {
questionId: string
questionText: string
questionCondition?: GekanatorQuestionCondition
questionMode?: 'normal' | 'winning_run'
questionPurpose?: GekanatorQuestionPurpose
effectiveQuestion?: boolean
learningQuestion?: boolean
answer: GekanatorAnswerValue
originalAnswer: GekanatorAnswerValue }
@@ -163,6 +176,26 @@ const directExampleAnswerFor = (
return null
}
export const isLearnedSemanticQuestion = (
question: StoredGekanatorQuestion | GekanatorQuestion,
): boolean =>
question.kind === 'post_similarity'
&& question.source === 'user_suggested'
export const learnedSemanticSideForAnswer = (
answer: GekanatorAnswerValue | null,
): LearnedSemanticSide => {
if (answer === 'yes' || answer === 'partial')
return 'positive'
if (answer === 'no' || answer === 'probably_no')
return 'negative'
return 'unknown'
}
const countBy = <T extends string | number> (values: T[]): Map<T, number> => {
const counts = new Map<T, number> ()
values.forEach (value => counts.set (value, (counts.get (value) ?? 0) + 1))
@@ -285,8 +318,8 @@ const questionMatches = (
): boolean => {
const directAnswer = directExampleAnswerFor (question, post)
if (directAnswer)
return question.condition.type === 'post-similarity'
? directAnswer === question.condition.answer
return question.kind === 'post_similarity'
? learnedSemanticSideForAnswer (directAnswer) === 'positive'
: directAnswer === 'yes'
switch (question.condition.type)
@@ -328,6 +361,11 @@ export const expectedAnswerForQuestion = (
switch (question.condition.type)
{
case 'post-similarity':
if (question.condition.postId === post.id)
return question.condition.answer
return null
case 'tag':
case 'source':
case 'original-year':
@@ -338,12 +376,17 @@ export const expectedAnswerForQuestion = (
case 'title-has-ascii':
case 'title-contains':
return questionMatches (post, question) ? 'yes' : 'no'
case 'post-similarity':
return null
}
}
export const learnedSemanticSideForPost = (
question: StoredGekanatorQuestion | GekanatorQuestion | undefined,
post: Post | null,
): LearnedSemanticSide =>
learnedSemanticSideForAnswer (expectedAnswerForQuestion (question, post))
export const restoreGekanatorQuestion = (
question: StoredGekanatorQuestion,
): GekanatorQuestion => {
@@ -423,15 +466,15 @@ export const buildGekanatorQuestions = (
const originalYears = countBy (
posts
.map (originalYearOf)
.filter ((year): year is number => year !== null))
.filter ((year): year is number => year != null))
const originalMonths = countBy (
posts
.map (originalMonthOf)
.filter ((month): month is number => month !== null))
.filter ((month): month is number => month != null))
const originalMonthDays = countBy (
posts
.map (originalMonthDayOf)
.filter ((monthDay): monthDay is string => monthDay !== null))
.filter ((monthDay): monthDay is string => monthDay != null))
const titleLengthMedian = median (posts.map (post => post.title?.length ?? 0))
const titleWordCounts =
includeTitleContains