Better search rankings

This commit is contained in:
Mr. Stallion 2020-11-21 14:41:08 -06:00
parent e8c78079b1
commit 4ceee99520
13 changed files with 350 additions and 65 deletions

View File

@ -2,6 +2,9 @@
## Canary
* Use `Ctrl+Tab`, `Ctrl+Shift+Tab`, `Ctrl+PgDown`, and `Ctrl+PgUp` to switch between character tabs
* Better search rankings
* Really good matches get 'unicorn' tag
* Fixed IMGBB, Shadbase previews
## 1.4.1

View File

@ -91,24 +91,34 @@
const xc = core.cache.profileCache.getSync(x.name);
const yc = core.cache.profileCache.getSync(y.name);
if (xc && !yc) {
if(xc && !yc) {
return -1;
}
if (!xc && yc) {
if(!xc && yc) {
return 1;
}
if (xc && yc) {
if (xc.matchScore > yc.matchScore)
if(xc && yc) {
if(xc.match.matchScore > yc.match.matchScore)
return -1;
if (xc.matchScore < yc.matchScore)
if(xc.match.matchScore < yc.match.matchScore)
return 1;
if(xc.match.searchScore > yc.match.searchScore)
return -1;
if(xc.match.searchScore < yc.match.searchScore)
return 1;
}
if(x.name < y.name) return -1;
if(x.name > y.name) return 1;
if(x.name < y.name)
return -1;
if(x.name > y.name)
return 1;
return 0;
}

View File

@ -777,11 +777,23 @@
border-radius: 3px;
color: rgba(255, 255, 255, 0.8);
font-size: 75%;
padding-top: 0;
padding-bottom: 0;
text-align: center;
display: inline-block;
text-transform: uppercase;
line-height: 100%;
padding-top: 2px;
padding-bottom: 2px;
&.unicorn {
background-color: #00adad;
border: solid 1px #1d9a9a;
box-shadow: 0 0 5px 0 rgba(255, 255, 255, 0.5);
&::before {
content: '🦄';
padding-right:3px
}
}
&.match {
background-color: var(--scoreMatchBg);

View File

@ -6,7 +6,7 @@
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 { Matcher, Score, Scoring } from '../learn/matcher';
import core from './core';
import { EventBus } from './preview/event-bus';
@ -37,7 +37,7 @@ export interface StatusClasses {
rankIcon: string | null;
statusClass: string | null;
matchClass: string | null;
matchScore: number | null;
matchScore: number | string | null;
userClass: string;
isBookmark: boolean;
}
@ -71,8 +71,13 @@ export function getStatusClasses(
const cache = core.cache.profileCache.getSync(character.name);
if (cache) {
matchClass = `match-found ${Score.getClasses(cache.matchScore)}`;
matchScore = cache.matchScore;
if ((cache.match.searchScore > Matcher.UNICORN_LEVEL) && (cache.match.matchScore === Scoring.MATCH)) {
matchClass = 'match-found unicorn';
matchScore = 'unicorn';
} else {
matchClass = `match-found ${Score.getClasses(cache.match.matchScore)}`;
matchScore = cache.match.matchScore;
}
} else {
/* tslint:disable-next-line no-floating-promises */
core.cache.addProfile(character.name);
@ -126,7 +131,7 @@ export default class UserView extends Vue {
rankIcon: string | null = null;
statusClass: string | null = null;
matchClass: string | null = null;
matchScore: number | null = null;
matchScore: number | string | null = null;
// tslint:disable-next-line no-any
scoreWatcher: ((event: any) => void) | null = null;
@ -197,8 +202,11 @@ export default class UserView extends Vue {
}
getMatchScoreTitle(score: number | null): string {
getMatchScoreTitle(score: number | string | null): string {
switch (score) {
case 'unicorn':
return 'Unicorn';
case Scoring.MATCH:
return 'Great';

View File

@ -1,6 +1,11 @@
<template>
<modal :action="`Ads for ${conversation.name}`" @submit="submit" ref="dialog" @open="load()" dialogClass="w-100"
:buttonText="l('conversationSettings.save')">
<div>
[] Randomize the order of the ads every time you start automated posting.
</div>
<div class="form-group ad-list" v-for="(ad, index) in ads">
<label :for="'ad' + conversation.key + '-' + index" class="control-label">Ad #{{(index + 1)}}
<a v-if="(index > 0)" @click="moveAdUp(index)" title="Move Up"><i class="fa fa-arrow-up"></i></a>

View File

@ -1,4 +1,4 @@
<template>
<template>
<div class="character-preview">
<div v-if="match && character" class="row">
<div class="col-2">
@ -6,7 +6,10 @@
</div>
<div class="col-10">
<h1><span class="character-name" :class="(statusClasses || {}).userClass">{{ character.character.name }}</span></h1>
<h1 class="user-view">
<span class="character-name" :class="(statusClasses || {}).userClass">{{ character.character.name }}</span>
<span v-if="((statusClasses) && (statusClasses.matchScore === 'unicorn'))" :class="(statusClasses || {}).matchClass">Unicorn</span>
</h1>
<h3>{{ getOnlineStatus() }}</h3>
<div class="summary">
@ -23,6 +26,10 @@
<match-tags v-if="match" :match="match"></match-tags>
<!-- <div v-if="customs">-->
<!-- <span v-for="c in customs" :class="Score.getClasses(c.score)">{{c.name}}</span>-->
<!-- </div>-->
<div class="status-message" v-if="statusMessage">
<h4>Status <span v-if="latestAd && (statusMessage === latestAd.message)">&amp; Latest Ad</span></h4>
<bbcode :text="statusMessage"></bbcode>
@ -41,12 +48,12 @@
</template>
<script lang="ts">
import { Component, Prop } from '@f-list/vue-ts';
import { Component, Hook, Prop } from '@f-list/vue-ts';
import Vue from 'vue';
import core from '../core';
import { methods } from '../../site/character_page/data_store';
import {Character as ComplexCharacter} from '../../site/character_page/interfaces';
import { Matcher, MatchReport } from '../../learn/matcher';
import { Matcher, MatchReport, Score } from '../../learn/matcher';
import { Character as CharacterStatus } from '../../fchat';
import { getStatusClasses, StatusClasses } from '../UserView.vue';
import * as _ from 'lodash';
@ -56,13 +63,19 @@ import * as Utils from '../../site/utils';
import MatchTags from './MatchTags.vue';
import {
furryPreferenceMapping,
Gender,
Gender, kinkMapping,
Orientation,
Species,
SubDomRole,
TagId
} from '../../learn/matcher-types';
import { BBCodeView } from '../../bbcode/view';
import { EventBus } from './event-bus';
import { Character, CustomKink } from '../../interfaces';
interface CustomKinkWithScore extends CustomKink {
score: number;
}
@Component({
@ -93,11 +106,53 @@ export default class CharacterPreview extends Vue {
formatTime = formatTime;
readonly avatarUrl = Utils.avatarURL;
TagId = TagId;
async load(characterName: string): Promise<void> {
TagId = TagId;
Score = Score;
scoreWatcher: ((event: any) => void) | null = null;
customs?: CustomKinkWithScore[];
@Hook('mounted')
mounted(): void {
// tslint:disable-next-line no-unsafe-any no-any
this.scoreWatcher = async(event: {character: Character, score: number}): Promise<void> => {
// console.log('scoreWatcher', event);
if (
(event.character)
&& (this.characterName)
&& (event.character.name === this.characterName)
) {
await this.load(this.characterName, true);
}
};
EventBus.$on(
'character-score',
this.scoreWatcher
);
}
@Hook('beforeDestroy')
beforeDestroy(): void {
if (this.scoreWatcher) {
EventBus.$off(
'character-score',
this.scoreWatcher
);
this.scoreWatcher = null;
}
}
async load(characterName: string, force: boolean = false): Promise<void> {
if (
(this.characterName === characterName)
&& (!force)
&& (this.match)
&& (this.character)
&& (this.ownCharacter)
@ -112,6 +167,7 @@ export default class CharacterPreview extends Vue {
this.match = undefined;
this.character = undefined;
this.customs = undefined;
this.ownCharacter = core.characters.ownProfile;
this.updateOnlineStatus();
@ -120,6 +176,7 @@ export default class CharacterPreview extends Vue {
this.character = await this.getCharacterData(characterName);
this.match = Matcher.identifyBestMatchReport(this.ownCharacter.character, this.character.character);
this.updateCustoms();
this.updateDetails();
}
@ -133,10 +190,9 @@ export default class CharacterPreview extends Vue {
}
this.statusMessage = this.onlineCharacter.statusText;
this.statusClasses = getStatusClasses(this.onlineCharacter, undefined, true, false, false);
this.statusClasses = getStatusClasses(this.onlineCharacter, undefined, true, false, true);
}
updateAdStatus(): void {
const cache = core.cache.adCache.get(this.characterName!);
@ -149,6 +205,25 @@ export default class CharacterPreview extends Vue {
}
updateCustoms(): void {
this.customs = _.orderBy(
_.map(
_.reject(this.character!.character.customs || [], (c) => _.isUndefined(c)) as CustomKink[],
(c: CustomKink) => _.assign(
{},
c,
{
score: kinkMapping[c.choice],
name: c.name.trim().replace(/^\W+/, '').replace(/\W+$/, '')
}
)
),
['score', 'name'],
['desc', 'asc']
);
}
updateDetails(): void {
if (!this.match) {
this.age = undefined;
@ -240,6 +315,10 @@ export default class CharacterPreview extends Vue {
border-radius: 0 5px 5px 5px;
border: 1px solid var(--secondary);
.unicorn {
margin-left: 8px;
}
.summary {
font-size: 125%;

View File

@ -112,7 +112,7 @@ class FListImagePreviewDomMutator {
}
const removeList = [];
const safeIds = ['flistWrapper', 'flistError', 'flistHider'];
const safeIds = ['flistWrapper', 'flistError', 'flistHider', 'flistStyle'];
const safeTags = this.safeTags;
for (const el of body.childNodes) {
@ -277,7 +277,17 @@ class FListImagePreviewDomMutator {
const el = document.createElement('style');
el.id = 'flistStyle';
el.textContent = `
html {
${this.getWrapperStyleOverrides()}
}
body {
${this.getWrapperStyleOverrides()}
}
#flistWrapper img, #flistWrapper video {
${this.getImageStyleOverrides()}
}

View File

@ -172,6 +172,7 @@ export class ImageDomMutator {
this.add('furaffinity.net', this.getBaseJsMutatorScript(['#submissionImg', 'video', 'img']));
this.add('rule34.paheal.net', this.getBaseJsMutatorScript(['#main_image', 'video', 'img']));
this.add('xhamster.com', this.getBaseJsMutatorScript(['#photo_slider video', '#photo_slider img', 'video', 'img']));
this.add('shadbase.com', this.getBaseJsMutatorScript(['#comic video', '#comic img', 'video', 'img']));
this.add(
'pornhub.com',

View File

@ -97,5 +97,7 @@
[url=https://xhamster.com/videos/letsdoeit-check-out-the-sexiest-massage-sex-compilation-now-xh7hyIG]xHamster Video[/url]
[url=https://ibb.co/jMcYcPx]Imgbb[/url]
Broken
https://vimeo.com/265884960

View File

@ -66,7 +66,7 @@ export class CacheManager {
const c = await this.profileCache.get(name);
if (c) {
this.updateAdScoringForProfile(c.character, c.matchScore);
this.updateAdScoringForProfile(c.character, c.match.matchScore);
return;
}
}
@ -98,7 +98,7 @@ export class CacheManager {
const r = await this.profileCache.register(c);
this.updateAdScoringForProfile(c, r.matchScore);
this.updateAdScoringForProfile(c, r.match.matchScore);
return c;
} catch (err) {
@ -395,10 +395,10 @@ export class CacheManager {
// console.log(`Re-scored character ${char.name} to ${p.matchScore}`);
// }
msg.score = p.matchScore;
msg.score = p.match.matchScore;
if (populateAll) {
this.populateAllConversationsWithScore(char.name, p.matchScore);
this.populateAllConversationsWithScore(char.name, p.match.matchScore);
}
}

View File

@ -242,7 +242,7 @@ export const speciesMapping: SpeciesMap = {
gen('(beast|anthro|furry)')
],
[Species.Human]: ['human', 'homo sapiens', 'human.*', 'homo[ -]?sapi[ea]ns?', 'woman', 'h[uo]+m[aie]n', 'humaine?',
[Species.Human]: ['human', 'homo sapiens', 'human.*', 'homo[ -]?sapi[ea]ns?', 'woman', 'hy?[uo]+m[aie]n', 'humaine?',
'meat[ -]?popsicle',
// where should these go?
'angel', 'neph[ai]l[ei]m', 'arch[ -]?angel'
@ -257,8 +257,8 @@ export const speciesMapping: SpeciesMap = {
'terrier', 'bull[ -]?terrier', 'australian[ -]?shepherd', 'australian[ -]?shep[h]?ard', 'german[ -]?shep[h]?([ea]rd)?',
'malinois', 'woof', 'labrador', 'collie', 'canis', 'lupus', 'canid', 'chihuahua', 'poodle', 'chinchilla',
'chow[ -]?chow', 'corgi', 'anubis', 'beagle', '.*wolf', 'direwolf', 'pointer', 'dhole', 'worg(en)?',
'anubian', 'dalmatian', 'dalmation', 'inumimi', 'lupine', 'malamute', 'mastiff', 'mutt', 'rottweill?er', 'shih[ -]?tzu',
'vallhund', 'puppy', 'oo?kami', 'great[ -]?dane', 'golden[ -]?(retriever|lab|labrador)', 'cocker[ -]?spaniel', 'samoyed', 'awoo',
'anubian', 'dalmatian', 'dalmation', 'inumimi', 'lupine', 'malamute', 'mastiff', 'mutt', 'rott?w[ea]ill?er', 'shih[ -]?tzu',
'vallhund', 'puppy', 'oo?kami', 'great[ -]?dane', 'golden[ -]?(retriever|lab|labrador)', 'cocker[ -]?spaniel', 'samm?oyed', 'awoo+',
'borzoi', 'spaniel', 'ookamimimi', 'jakkarumimi', 'chinchiramimi', 'woffo', 'wuff', 'wolfdog', 'setter', 'papillon',
'🐶', '🐺', '🐕', '🐩', 'aussie[ -]?doodle', 'shiba', 'inu', 'veil[ -]?hound', 'timber[ -]?wolf', 'hell[ -]?hound', 'hound',
'kangal', 'behemoth', 'mongrel', 'fenrir', 'v[aá]na[r]?gand[r]?', 'crux', 'st.?[ -]?bernard',
@ -313,7 +313,7 @@ export const speciesMapping: SpeciesMap = {
'vaporeon', 'reshiram', 'quilava', 'decidueye', 'marshadow', 'weavile', 'zubat', 'buizel', 'latias', 'nidorina',
'chandelur(e|ia)', 'sneasel', 'rockruff', 'lugia', 'komala', 'meowstic', 'leafeon', 'purrloin', 'pokemorph',
'houndour', 'zoroark', 'mightyena', 'mew', 'nidoqueen', 'zangoose', 'goodra', 'flygon', 'dialga', 'pansear',
'bibarel', 'charmeleon',
'bibarel', 'charmeleon', 'lapras',
// digimon
'gatomon', 'impmon', 'guilmon'
@ -439,7 +439,7 @@ export const speciesMapping: SpeciesMap = {
'hutt', 'klyntar', 'twi\'?lek', 'sangheili', 'salarian', 't[\']?vaoan', 'yautja', 'zabrak'],
[Species.Robot]: ['android', 'cyborg', 'gynoid', 'automaton', 'robot', 'transformer', 'cybertronian', 'reploid', 'synth', 'ai',
'realian', 'replicant'],
'realian', 'replicant', 'synthetic'],
[Species.Hub]: ['hub', 'varies', 'various', 'variable', 'many', 'flexible', 'any', 'partner preference']
};

View File

@ -31,6 +31,7 @@ export interface MatchReport {
themMultiSpecies: boolean;
merged: MatchResultScores;
score: Scoring | null;
details: MatchScoreDetails;
}
export interface MatchResultCharacterInfo {
@ -48,6 +49,11 @@ export interface MatchResultScores {
[TagId.Species]: Score;
}
export interface MatchScoreDetails {
totalScoreDimensions: number;
dimensionsAtScoreLevel: number;
}
export interface MatchResult {
you: Character,
them: Character,
@ -171,6 +177,8 @@ export class Matcher {
readonly yourAnalysis: CharacterAnalysis;
readonly theirAnalysis: CharacterAnalysis;
static readonly UNICORN_LEVEL = 5.5;
constructor(you: Character, them: Character, yourAnalysis?: CharacterAnalysis, theirAnalysis?: CharacterAnalysis) {
this.you = you;
@ -196,11 +204,18 @@ export class Matcher {
youMultiSpecies: false,
themMultiSpecies: false,
merged: Matcher.mergeResults(youThemMatch, themYouMatch),
score: null
score: null,
details: {
totalScoreDimensions: 0,
dimensionsAtScoreLevel: 0
}
};
report.score = Matcher.calculateReportScore(report);
report.details.totalScoreDimensions = Matcher.countScoresTotal(report);
report.details.dimensionsAtScoreLevel = Matcher.countScoresAtLevel(report, report.score) || 0;
return report;
}
@ -228,13 +243,20 @@ export class Matcher {
youMultiSpecies: (yourCharacterAnalyses.length > 1),
themMultiSpecies: (theirCharacterAnalyses.length > 1),
merged: Matcher.mergeResults(youThemMatch, themYouMatch),
score: null
score: null,
details: {
totalScoreDimensions: 0,
dimensionsAtScoreLevel: 0
}
};
report.score = Matcher.calculateReportScore(report);
const scoreLevelCount = Matcher.countScoresAtLevel(report, report.score);
report.details.totalScoreDimensions = Matcher.countScoresTotal(report);
report.details.dimensionsAtScoreLevel = scoreLevelCount || 0;
if (
(bestScore === null)
|| (
@ -251,7 +273,10 @@ export class Matcher {
}
}
log.debug('report.identify.best', {buildTime: Date.now() - reportStartTime});
log.debug(
'report.identify.best',
{buildTime: Date.now() - reportStartTime, variations: yourCharacterAnalyses.length * theirCharacterAnalyses.length}
);
return bestReport!;
}
@ -301,21 +326,6 @@ export class Matcher {
);
}
static countScoresAtLevel(m: MatchReport, scoreLevel: Scoring | null): number | null {
if (scoreLevel === null) {
return null;
}
const yourScores = _.values(m.you.scores);
const theirScores = _.values(m.them.scores);
return _.reduce(
_.concat(yourScores, theirScores),
(accum: number, score: Score) => accum + (score.score === scoreLevel ? 1 : 0),
0
);
}
static calculateReportScore(m: MatchReport): Scoring | null {
const yourScores = _.values(m.you.scores);
const theirScores = _.values(m.them.scores);
@ -647,7 +657,23 @@ export class Matcher {
if ((!yourSubDomRole) || (!theirSubDomRole))
return new Score(Scoring.NEUTRAL);
if ((yourSubDomRole === SubDomRole.AlwaysDominant) || (yourSubDomRole === SubDomRole.UsuallyDominant)) {
if (yourSubDomRole === SubDomRole.UsuallyDominant) {
if (theirSubDomRole === SubDomRole.Switch)
return new Score(Scoring.MATCH, `Loves <span>switches</span>`);
if ((theirSubDomRole === SubDomRole.AlwaysSubmissive) || (theirSubDomRole === SubDomRole.UsuallySubmissive))
return new Score(Scoring.MATCH, `Loves <span>submissives</span>`);
if (yourRoleReversalPreference === KinkPreference.Favorite)
return new Score(Scoring.MATCH, `Loves <span>role reversal</span>`);
if (yourRoleReversalPreference === KinkPreference.Yes)
return new Score(Scoring.MATCH, `Likes <span>role reversal</span>`);
return new Score(Scoring.WEAK_MISMATCH, 'Hesitant about <span>dominants</span>');
}
if (yourSubDomRole === SubDomRole.AlwaysDominant) {
if (theirSubDomRole === SubDomRole.Switch)
return new Score(Scoring.WEAK_MATCH, `Likes <span>switches</span>`);
@ -666,7 +692,23 @@ export class Matcher {
return new Score(Scoring.WEAK_MISMATCH, 'Hesitant about <span>dominants</span>');
}
if ((yourSubDomRole === SubDomRole.AlwaysSubmissive) || (yourSubDomRole === SubDomRole.UsuallySubmissive)) {
if (yourSubDomRole === SubDomRole.UsuallySubmissive) {
if (theirSubDomRole === SubDomRole.Switch)
return new Score(Scoring.MATCH, `Loves <span>switches</span>`);
if ((theirSubDomRole === SubDomRole.AlwaysDominant) || (theirSubDomRole === SubDomRole.UsuallyDominant))
return new Score(Scoring.MATCH, `Loves <span>dominants</span>`);
if (yourRoleReversalPreference === KinkPreference.Favorite)
return new Score(Scoring.MATCH, `Loves <span>role reversal</span>`);
if (yourRoleReversalPreference === KinkPreference.Yes)
return new Score(Scoring.MATCH, `Likes <span>role reversal</span>`);
return new Score(Scoring.WEAK_MISMATCH, 'Hesitant about <span>submissives</span>');
}
if (yourSubDomRole === SubDomRole.AlwaysSubmissive) {
if (theirSubDomRole === SubDomRole.Switch)
return new Score(Scoring.WEAK_MATCH, `Likes <span>switches</span>`);
@ -902,4 +944,105 @@ export class Matcher {
return null;
}
static countScoresAtLevel(
m: MatchReport, scoreLevel: Scoring | null,
skipYours: boolean = false,
skipTheirs: boolean = false
): number | null {
if (scoreLevel === null) {
return null;
}
const yourScores = skipYours ? [] : _.values(m.you.scores);
const theirScores = skipTheirs ? [] : _.values(m.them.scores);
return _.reduce(
_.concat(yourScores, theirScores),
(accum: number, score: Score) => accum + (score.score === scoreLevel ? 1 : 0),
0
);
}
static countScoresAboveLevel(
m: MatchReport, scoreLevel: Scoring | null,
skipYours: boolean = false,
skipTheirs: boolean = false
): number {
if (scoreLevel === null) {
return 0;
}
const yourScores = skipYours ? [] : _.values(m.you.scores);
const theirScores = skipTheirs ? [] : _.values(m.them.scores);
return _.reduce(
_.concat(yourScores, theirScores),
(accum: number, score: Score) => accum + ((score.score > scoreLevel) && (score.score !== Scoring.NEUTRAL) ? 1 : 0),
0
);
}
static countScoresTotal(m: MatchReport): number {
return _.values(m.you.scores).length
+ _.values(m.them.scores).length;
}
static calculateSearchScoreForMatch(
score: Scoring,
match: MatchReport
): number {
const totalScoreDimensions = match ? Matcher.countScoresTotal(match) : 0;
const dimensionsAtScoreLevel = match ? (Matcher.countScoresAtLevel(match, score) || 0) : 0;
const dimensionsAboveScoreLevel = match ? (Matcher.countScoresAboveLevel(match, Math.max(score, Scoring.WEAK_MATCH))) : 0;
let atLevelScore = 0;
let aboveLevelScore = 0;
let theirAtLevelDimensions = 0;
let atLevelMul = 0;
let theirAboveLevelDimensions = 0;
let aboveLevelMul = 0;
if ((dimensionsAtScoreLevel > 0) && (totalScoreDimensions > 0)) {
const matchRatio = dimensionsAtScoreLevel / totalScoreDimensions;
theirAtLevelDimensions = Matcher.countScoresAtLevel(match, score, true, false) || 0;
// 1.0 == bad balance; 0.0 == ideal balance
atLevelMul = Math.abs((theirAtLevelDimensions / (dimensionsAtScoreLevel)) - 0.5) * 2;
atLevelScore = (1 - (atLevelMul * 0.5)) * Math.pow(dimensionsAtScoreLevel, matchRatio);
}
if ((dimensionsAboveScoreLevel > 0) && (totalScoreDimensions > 0)) {
const matchRatio = dimensionsAboveScoreLevel / totalScoreDimensions;
theirAboveLevelDimensions = Matcher.countScoresAboveLevel(match, score, true, false) || 0;
// 1.0 == bad balance; 0.0 == ideal balance
aboveLevelMul = Math.abs((theirAboveLevelDimensions / (dimensionsAboveScoreLevel)) - 0.5) * 2;
aboveLevelScore = (1 - (aboveLevelMul * 0.5)) * Math.pow(dimensionsAboveScoreLevel, matchRatio);
}
log.debug(
'report.score.search',
{
you: match.you.you.name,
them: match.them.you.name,
searchScore: (atLevelScore + aboveLevelScore),
atLevelScore,
aboveLevelScore,
atLevelMul,
aboveLevelMul,
dimensionsAboveScoreLevel,
dimensionsAtScoreLevel,
theirAtLevelDimensions,
theirAboveLevelDimensions
}
);
return (atLevelScore + aboveLevelScore);
}
}

View File

@ -3,7 +3,7 @@ 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, Scoring } from './matcher';
import { Matcher, MatchReport, Scoring } from './matcher';
import { PermanentIndexedStore } from './store/sql-store';
import { CharacterImage, SimpleCharacter } from '../interfaces';
@ -16,7 +16,6 @@ export interface MetaRecord {
lastMetaFetched: Date | null;
}
export interface CountRecord {
groupCount: number | null;
friendCount: number | null;
@ -24,12 +23,20 @@ export interface CountRecord {
lastCounted: number | null;
}
export interface CharacterMatchSummary {
matchScore: number;
// dimensionsAtScoreLevel: number;
// dimensionsAboveScoreLevel: number;
// totalScoreDimensions: number;
searchScore: number;
}
export interface CharacterCacheRecord {
character: ComplexCharacter;
lastFetched: Date;
added: Date;
matchScore: number;
// counts?: CountRecord;
match: CharacterMatchSummary;
meta?: MetaRecord;
}
@ -135,12 +142,19 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
async register(c: ComplexCharacter, skipStore: boolean = false): Promise<CharacterCacheRecord> {
const k = AsyncCache.nameKey(c.character.name);
const score = ProfileCache.score(c);
const match = ProfileCache.match(c);
const score = (!match || match.score === null) ? Scoring.NEUTRAL : match.score;
if (score === 0) {
console.log(`Storing score 0 for character ${c.character.name}`);
}
// const totalScoreDimensions = match ? Matcher.countScoresTotal(match) : 0;
// const dimensionsAtScoreLevel = match ? (Matcher.countScoresAtLevel(match, score) || 0) : 0;
// const dimensionsAboveScoreLevel = match ? (Matcher.countScoresAboveLevel(match, Math.max(score, Scoring.WEAK_MATCH))) : 0;
const searchScore = match ? Matcher.calculateSearchScoreForMatch(score, match) : 0;
const matchDetails = { matchScore: score, searchScore };
if ((this.store) && (!skipStore)) {
await this.store.storeProfile(c);
}
@ -150,7 +164,7 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
rExisting.character = c;
rExisting.lastFetched = new Date();
rExisting.matchScore = score;
rExisting.match = matchDetails;
return rExisting;
}
@ -159,7 +173,7 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
character: c,
lastFetched: new Date(),
added: new Date(),
matchScore: score
match: matchDetails
};
this.cache[k] = rNew;
@ -168,15 +182,13 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
}
static score(c: ComplexCharacter): number {
static match(c: ComplexCharacter): MatchReport | null {
const you = core.characters.ownProfile;
if (!you) {
return 0;
return null;
}
const m = Matcher.identifyBestMatchReport(you.character, c.character);
return m.score === null ? Scoring.NEUTRAL : m.score;
return Matcher.identifyBestMatchReport(you.character, c.character);
}
}