Post length comparison

This commit is contained in:
Mr. Stallion 2021-03-25 15:53:37 -05:00
parent 81ad12b03f
commit 34cb62b1ad
8 changed files with 195 additions and 60 deletions

View File

@ -6,10 +6,10 @@
import { Component, Hook, Prop, Watch } from '@f-list/vue-ts';
import Vue from 'vue';
import {Channel, Character} from '../fchat';
import { Score, Scoring } from '../learn/matcher';
import { Score } from '../learn/matcher';
import core from './core';
import { EventBus } from './preview/event-bus';
import { kinkMatchWeights } from '../learn/matcher-types';
import { kinkMatchWeights, Scoring } from '../learn/matcher-types';
export function getStatusIcon(status: Character.Status): string {

View File

@ -1,12 +1,13 @@
import { Component, Hook, Prop } from '@f-list/vue-ts';
import {CreateElement, default as Vue, VNode, VNodeChildrenArrayContents} from 'vue';
import {Channel} from '../fchat';
import { Score, Scoring } from '../learn/matcher';
import { Score } from '../learn/matcher';
import {BBCodeView} from '../bbcode/view';
import {formatTime} from './common';
import core from './core';
import {Conversation} from './interfaces';
import UserView from './UserView.vue';
import { Scoring } from '../learn/matcher-types';
const userPostfix: {[key: number]: string | undefined} = {
[Conversation.Message.Type.Message]: ': ',

View File

@ -94,7 +94,7 @@
async mounted(): Promise<void> {
log.debug('init.window.mounting');
// top bar devtools
// browserWindow.webContents.openDevTools({ mode: 'detach' });
browserWindow.webContents.openDevTools({ mode: 'detach' });
updateSupportedLanguages(browserWindow.webContents.session.availableSpellCheckerLanguages);
@ -262,7 +262,7 @@
);
// tab devtools
// view.webContents.openDevTools();
view.webContents.openDevTools();
// console.log('ADD TAB LANGUAGES', getSafeLanguages(this.settings.spellcheckLang), this.settings.spellcheckLang);
view.webContents.session.setSpellCheckerLanguages(getSafeLanguages(this.settings.spellcheckLang));

View File

@ -1,3 +1,12 @@
export enum Scoring {
MATCH = 1,
WEAK_MATCH = 0.5,
NEUTRAL = 0,
WEAK_MISMATCH = -0.5,
MISMATCH = -1
}
export enum TagId {
Age = 1,
Orientation = 2,
@ -11,10 +20,23 @@ export enum TagId {
RelationshipStatus = 42,
Species = 9,
LanguagePreference = 49,
PostLength = 24,
Kinks = 99999
}
export enum PostLengthPreference {
NoPreference = 63,
VeryShort_1_2 = 26,
Short_2_4 = 27,
SemiParagraph_4_7 = 28,
Paragraph_7_10 = 60,
StrongParagraph_10_14 = 61,
MultiParagraph_14_25 = 62
}
export enum Gender {
Male = 1,
Female = 2,
@ -103,6 +125,72 @@ export const furryPreferenceMapping = {
};
export const postLengthPreferenceMapping = {
[PostLengthPreference.MultiParagraph_14_25]: 'multi-paragraph posts',
[PostLengthPreference.StrongParagraph_10_14]: 'strong paragraph posts',
[PostLengthPreference.Paragraph_7_10]: 'paragraph posts',
[PostLengthPreference.SemiParagraph_4_7]: 'semi-paragraph posts',
[PostLengthPreference.Short_2_4]: 'short posts',
[PostLengthPreference.VeryShort_1_2]: 'very short posts'
};
export const postLengthPreferenceScoreMapping = {
[PostLengthPreference.MultiParagraph_14_25]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.MATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.MATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.WEAK_MATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.WEAK_MISMATCH,
[PostLengthPreference.Short_2_4]: Scoring.MISMATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.MISMATCH
},
[PostLengthPreference.StrongParagraph_10_14]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.MATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.MATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.MATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.WEAK_MISMATCH,
[PostLengthPreference.Short_2_4]: Scoring.MISMATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.MISMATCH
},
[PostLengthPreference.Paragraph_7_10]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.WEAK_MATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.MATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.MATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.WEAK_MATCH,
[PostLengthPreference.Short_2_4]: Scoring.MISMATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.MISMATCH
},
[PostLengthPreference.SemiParagraph_4_7]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.MISMATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.WEAK_MISMATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.WEAK_MATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.MATCH,
[PostLengthPreference.Short_2_4]: Scoring.MATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.WEAK_MATCH
},
[PostLengthPreference.Short_2_4]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.MISMATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.MISMATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.WEAK_MISMATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.WEAK_MATCH,
[PostLengthPreference.Short_2_4]: Scoring.MATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.MATCH
},
[PostLengthPreference.VeryShort_1_2]: {
[PostLengthPreference.MultiParagraph_14_25]: Scoring.MISMATCH,
[PostLengthPreference.StrongParagraph_10_14]: Scoring.MISMATCH,
[PostLengthPreference.Paragraph_7_10]: Scoring.MISMATCH,
[PostLengthPreference.SemiParagraph_4_7]: Scoring.WEAK_MATCH,
[PostLengthPreference.Short_2_4]: Scoring.MATCH,
[PostLengthPreference.VeryShort_1_2]: Scoring.MATCH
}
};
export interface GenderKinkIdMap {
[key: number]: Kink
}
@ -485,37 +573,37 @@ export interface SpeciesMappingCache {
export const kinkMatchWeights = {
logBase: 10,
weakMismatchThreshold: 0.3,
weakMatchThreshold: 0.3,
unicornThreshold: 8.0
// logBase: 10,
weakMismatchThreshold: 16,
weakMatchThreshold: 16,
unicornThreshold: 9
};
export const kinkMatchScoreMap = {
favorite: {
favorite: 0.5,
yes: 0.25,
maybe: -0.5,
no: -2
favorite: 1,
yes: 0.5,
maybe: -0.65,
no: -1.5
},
yes: {
favorite: 0.3,
yes: 0.2,
maybe: -0.15,
favorite: 0.5,
yes: 0.5,
maybe: -0.25,
no: -0.5
},
maybe: {
favorite: -0.5,
yes: -0.2,
yes: -0.25,
maybe: 0,
no: 0
},
no: {
favorite: -2,
yes: -0.5,
favorite: -1.5,
yes: -0.65,
maybe: 0,
no: 0
}
@ -571,6 +659,7 @@ export interface KinkBucketScore {
score: number;
count: number;
weighted: number;
total: number;
}
export interface MatchResultKinkScores {

View File

@ -3,22 +3,36 @@
import * as _ from 'lodash';
import { Character, CharacterInfotag, KinkChoice } from '../interfaces';
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
// tslint:disable-next-line ban-ts-ignore
// @ts-ignore
import anyAscii from 'any-ascii';
import {Store} from '../site/character_page/data_store';
import { Store } from '../site/character_page/data_store';
import {
BodyType, fchatGenderMap,
BodyType,
fchatGenderMap,
FurryPreference,
Gender, genderKinkMapping,
Kink, KinkBucketScore, kinkComparisonExclusionGroups, kinkComparisonExclusions, kinkComparisonSwaps,
kinkMapping, kinkMatchScoreMap, kinkMatchWeights,
KinkPreference, likelyHuman, mammalSpecies, nonAnthroSpecies,
Gender,
genderKinkMapping,
Kink,
KinkBucketScore,
kinkComparisonExclusionGroups,
kinkComparisonExclusions,
kinkComparisonSwaps,
kinkMapping,
kinkMatchScoreMap,
kinkMatchWeights,
KinkPreference,
likelyHuman,
mammalSpecies,
nonAnthroSpecies,
Orientation,
Species, SpeciesMap, speciesMapping, SpeciesMappingCache,
PostLengthPreference, postLengthPreferenceMapping, postLengthPreferenceScoreMapping, Scoring,
Species,
SpeciesMap,
speciesMapping,
SpeciesMappingCache,
speciesNames,
SubDomRole,
TagId
@ -68,13 +82,6 @@ export interface MatchResult {
theirAnalysis: CharacterAnalysis;
}
export enum Scoring {
MATCH = 1,
WEAK_MATCH = 0.5,
NEUTRAL = 0,
WEAK_MISMATCH = -0.5,
MISMATCH = -1
}
export interface ScoreClassMap {
[key: number]: string;
@ -141,6 +148,7 @@ export class CharacterAnalysis {
readonly furryPreference: FurryPreference | null;
readonly age: number | null;
readonly subDomRole: SubDomRole | null;
readonly postLengthPreference: PostLengthPreference | null;
readonly isAnthro: boolean | null;
readonly isHuman: boolean | null;
@ -154,6 +162,7 @@ export class CharacterAnalysis {
this.species = Matcher.species(c);
this.furryPreference = Matcher.getTagValueList(TagId.FurryPreference, c);
this.subDomRole = Matcher.getTagValueList(TagId.SubDomRole, c);
this.postLengthPreference = Matcher.getTagValueList(TagId.PostLength, c);
const ageTag = Matcher.getTagValue(TagId.Age, c);
@ -391,7 +400,8 @@ export class Matcher {
[TagId.FurryPreference]: this.resolveFurryPairingsScore(),
[TagId.Species]: this.resolveSpeciesScore(),
[TagId.SubDomRole]: this.resolveSubDomScore(),
[TagId.Kinks]: this.resolveKinkScore(pronoun)
[TagId.Kinks]: this.resolveKinkScore(pronoun),
[TagId.PostLength]: this.resolvePostLengthScore()
},
info: {
@ -487,6 +497,24 @@ export class Matcher {
return new Score(Scoring.NEUTRAL);
}
private resolvePostLengthScore(): Score {
const yourLength = this.yourAnalysis.postLengthPreference;
const theirLength = this.theirAnalysis.postLengthPreference;
if (
(!yourLength)
|| (!theirLength)
|| (yourLength === PostLengthPreference.NoPreference)
|| (theirLength === PostLengthPreference.NoPreference)
) {
return new Score(Scoring.NEUTRAL);
}
const score = postLengthPreferenceScoreMapping[yourLength][theirLength];
return this.formatScoring(score, postLengthPreferenceMapping[theirLength]);
}
private resolveSpeciesScore(): Score {
const you = this.you;
const theirAnalysis = this.theirAnalysis;
@ -568,23 +596,32 @@ export class Matcher {
private resolveKinkScore(pronoun: string): Score {
const kinkScore = this.resolveKinkBucketScore('all');
// const kinkScore = this.resolveKinkBucketScore('all');
log.debug('report.score.kink', this.them.name, this.you.name, kinkScore.count, kinkScore.score, kinkScore.weighted);
const scores = {
favorite: this.resolveKinkBucketScore('favorite'),
yes: this.resolveKinkBucketScore('yes'),
maybe: this.resolveKinkBucketScore('maybe'),
no: this.resolveKinkBucketScore('no')
};
if (kinkScore.weighted === 0) {
const weighted = scores.favorite.weighted + scores.yes.weighted + scores.maybe.weighted + scores.no.weighted;
log.debug('report.score.kink', this.them.name, this.you.name, scores, weighted);
if (weighted === 0) {
return new Score(Scoring.NEUTRAL);
}
if (kinkScore.weighted < 0) {
if (Math.abs(kinkScore.weighted) < kinkMatchWeights.weakMismatchThreshold) {
if (weighted < 0) {
if (Math.abs(weighted) < kinkMatchWeights.weakMismatchThreshold) {
return new Score(Scoring.WEAK_MISMATCH, `Hesitant about ${pronoun} <span>kinks</span>`);
}
return new Score(Scoring.MISMATCH, `Dislikes ${pronoun} <span>kinks</span>`);
}
if (Math.abs(kinkScore.weighted) < kinkMatchWeights.weakMatchThreshold) {
if (Math.abs(weighted) < kinkMatchWeights.weakMatchThreshold) {
return new Score(Scoring.WEAK_MATCH, `Likes ${pronoun} <span>kinks</span>`);
}
@ -793,42 +830,49 @@ export class Matcher {
(accum, yourKinkValue: any, yourKinkId: any) => {
const theirKinkId = (yourKinkId in kinkComparisonSwaps) ? kinkComparisonSwaps[yourKinkId] : yourKinkId;
const isExcluded = (yourKinkId in kinkComparisonExclusions)
|| ((Store.shared.kinks[yourKinkId]) && (Store.shared.kinks[yourKinkId].kink_group in kinkComparisonExclusionGroups));
const isBucketMatch = (yourKinkValue === bucket)
|| (bucket === 'all')
|| ((bucket === 'negative') && ((yourKinkValue === 'no') || (yourKinkValue === 'maybe')))
|| ((bucket === 'positive') && ((yourKinkValue === 'favorite') || (yourKinkValue === 'yes')));
if ((isBucketMatch) && (!isExcluded)) {
accum.total += 1;
}
if (
(!(theirKinkId in theirKinks))
|| (yourKinkId in kinkComparisonExclusions)
|| ((Store.shared.kinks[yourKinkId]) && (Store.shared.kinks[yourKinkId].kink_group in kinkComparisonExclusionGroups))
|| (isExcluded)
) {
return accum;
}
const theirKinkValue = theirKinks[theirKinkId] as any;
if (
(yourKinkValue === bucket)
|| (bucket === 'all')
|| ((bucket === 'negative') && ((yourKinkValue === 'no') || (yourKinkValue === 'maybe')))
|| ((bucket === 'positive') && ((yourKinkValue === 'favorite') || (yourKinkValue === 'yes')))
) {
if (isBucketMatch) {
return {
score: accum.score + this.getKinkMatchScore(yourKinkValue, theirKinkValue),
count: accum.count + 1
count: accum.count + 1,
total: accum.total
};
}
// missed += 1;
return accum;
},
{ score: 0, count: 0 }
{ score: 0, count: 0, total: 0 }
);
// const yourBucketCounts = this.countKinksByBucket(yourKinks);
// const theirBucketCounts = this.countKinksByBucket(theirKinks);
result.weighted = (result.count === 0)
result.weighted = ((result.count === 0) || (Math.abs(result.score) < 1))
? 0
: (
(Math.log(result.count) / Math.log(kinkMatchWeights.logBase)) // log 8 base
* (result.score / result.count)
Math.log(result.total) * Math.log(Math.abs(result.score)) * Math.sign(result.score)
// (Math.log(result.count) / Math.log(kinkMatchWeights.logBase)) // log 8 base
// * (result.score / result.count)
);
return result;
@ -873,7 +917,7 @@ export class Matcher {
private getKinkMatchScore(aValue: string, bValue: string): number {
return _.get(kinkMatchScoreMap, `${aValue}.${bValue}`, 0);
return _.get(kinkMatchScoreMap, `${aValue}.${bValue}`, 0) * 7; // forces range above 1.0
}

View File

@ -3,9 +3,10 @@ import * as _ from 'lodash';
import core from '../chat/core';
import {Character as ComplexCharacter, CharacterGroup, Guestbook} from '../site/character_page/interfaces';
import { AsyncCache } from './async-cache';
import { Matcher, MatchReport, Scoring } from './matcher';
import { Matcher, MatchReport } from './matcher';
import { PermanentIndexedStore } from './store/types';
import { CharacterImage, SimpleCharacter } from '../interfaces';
import { Scoring } from './matcher-types';
export interface MetaRecord {

View File

@ -59,7 +59,7 @@
}
theirInterestIsRelevant(id: number): boolean {
return ((id === TagId.FurryPreference) || (id === TagId.Orientation) || (id === TagId.SubDomRole));
return ((id === TagId.FurryPreference) || (id === TagId.Orientation) || (id === TagId.SubDomRole) || (id === TagId.PostLength));
}
yourInterestIsRelevant(id: number): boolean {

View File

@ -37,9 +37,9 @@
import * as _ from 'lodash';
import Vue from 'vue';
import * as Utils from '../utils';
import { Matcher, MatchReport, MatchResult, Score, Scoring } from '../../learn/matcher';
import { Matcher, MatchReport, MatchResult, Score } from '../../learn/matcher';
import core from '../../chat/core';
import { TagId } from '../../learn/matcher-types';
import { Scoring, TagId } from '../../learn/matcher-types';
export interface CssClassMap {
[key: string]: boolean;