Fluid species support

This commit is contained in:
Mr. Stallion 2020-10-04 16:30:54 -05:00
parent 361c6ffd5a
commit b52c7eec69
10 changed files with 472 additions and 325 deletions

View File

@ -60,7 +60,8 @@
import * as _ from 'lodash';
import {EventBus} from './preview/event-bus';
import CharacterSearchHistory from './CharacterSearchHistory.vue';
import { Matcher, Species, speciesNames } from '../learn/matcher';
import { Matcher } from '../learn/matcher';
import { Species, speciesNames } from '../learn/matcher-types';
type Options = {
kinks: SearchKink[],

View File

@ -4,7 +4,6 @@ import { ChannelAdEvent, ChannelMessageEvent, CharacterDataEvent, EventBus, Sele
import { Channel, Conversation } from '../chat/interfaces';
import { methods } from '../site/character_page/data_store';
import { Character as ComplexCharacter } from '../site/character_page/interfaces';
import { Gender } from './matcher';
import { AdCache } from './ad-cache';
import { ChannelConversationCache } from './channel-conversation-cache';
import { CharacterProfiler } from './character-profiler';
@ -17,6 +16,7 @@ import { Character } from '../fchat/interfaces';
import Bluebird from 'bluebird';
import ChatMessage = Conversation.ChatMessage;
import { GeneralSettings } from '../electron/common';
import { Gender } from './matcher-types';
export interface ProfileCacheQueueEntry {

View File

@ -1,9 +1,10 @@
import core from '../chat/core';
import { Character as CharacterFChatInf } from '../fchat';
import { Character as ComplexCharacter } from '../site/character_page/interfaces';
import { Matcher, TagId } from './matcher';
import { Matcher } from './matcher';
import { AdCache } from './ad-cache';
import { ProfileCacheQueueEntry } from './cache-manager';
import { TagId } from './matcher-types';
export class CharacterProfiler {
@ -98,4 +99,4 @@ export class CharacterProfiler {
return -0.5; // has been advertising, but not recently, so likely busy
}
}
}

264
learn/matcher-types.ts Normal file
View File

@ -0,0 +1,264 @@
export enum TagId {
Age = 1,
Orientation = 2,
Gender = 3,
Build = 13,
FurryPreference = 29,
SubDomRole = 15,
Position = 41,
BodyType = 51,
ApparentAge = 64,
RelationshipStatus = 42,
Species = 9,
LanguagePreference = 49
}
export enum Gender {
Male = 1,
Female = 2,
Transgender = 3,
Herm = 32,
MaleHerm = 51,
Cuntboy = 69,
None = 105,
Shemale = 141
}
export enum SubDomRole {
AlwaysSubmissive = 7,
UsuallySubmissive = 8,
Switch = 9,
UsuallyDominant = 10,
AlwaysDominant = 11
}
export enum Orientation {
Straight = 4,
Gay = 5,
Bisexual = 6,
Asexual = 7,
Unsure = 8,
BiMalePreference = 89,
BiFemalePreference = 90,
Pansexual = 127,
BiCurious = 128
}
export enum BodyType {
Anthro = 122,
Feral = 121,
Morphable = 123,
Varies = 124,
Other = 125,
Androgynous = 126,
Human = 143,
Taur = 145
}
export enum KinkPreference {
Favorite = 1,
Yes = 0.5,
Maybe = -0.5,
No = -1
}
export enum Kink {
Females = 554,
MaleHerms = 552,
Males = 553,
Transgenders = 551,
Herms = 132,
Shemales = 356,
Cuntboys = 231,
OlderCharacters = 109,
YoungerCharacters = 197,
Ageplay = 196,
UnderageCharacters = 207,
RoleReversal = 408,
AnthroCharacters = 587,
Humans = 609,
Mammals = 224
}
export enum FurryPreference {
FurriesOnly = 39,
FursAndHumans = 40,
HumansOnly = 41,
HumansPreferredFurriesOk = 150,
FurriesPreferredHumansOk = 149
}
export interface GenderKinkIdMap {
[key: number]: Kink
}
export const genderKinkMapping: GenderKinkIdMap = {
[Gender.Female]: Kink.Females,
[Gender.Male]: Kink.Males,
[Gender.Cuntboy]: Kink.Cuntboys,
[Gender.Herm]: Kink.Herms,
[Gender.MaleHerm]: Kink.MaleHerms,
[Gender.Shemale]: Kink.Shemales,
[Gender.Transgender]: Kink.Transgenders
};
// if no species and 'no furry characters', === human
// if no species and dislike 'anthro characters' === human
export enum Species {
Human = 609,
Humanoid = 131,
Bovine = 318,
Equine = 236,
Feline = 212,
Canine = 226,
Caprinae = 558,
Demon = 7,
Divinity = 530,
Vulpine = 213,
Avian = 215,
Amphibian = 223,
Cervine = 227,
Insect = 237,
Lapine = 214,
Musteline = 328,
Dragon = 228,
Procyon = 325,
Rodent = 283,
Ursine = 326,
MarineMammal = 309,
Primate = 613,
Elf = 611,
Orc = 615,
Fish = 608,
Reptile = 225,
Marsupial = 322,
Anthro = 587,
Robot = 161,
Hyaenidae = 321,
Mephitidae = 323,
Bat = 451,
Alien = 281,
Dinosaur = 610,
Pokemon = 504,
Fae = 612,
Taur = 68,
Vampire = 182,
Naga = 619,
Monster = 483,
Minotaur = 12121212,
Giraffe = 13131313,
Rhinoceros = 14141414
}
export const nonAnthroSpecies = [
Species.Human, Species.Elf, Species.Orc, Species.Humanoid,
Species.Demon, Species.Divinity, Species.Alien, Species.Robot,
Species.Fae, Species.Vampire
];
export const mammalSpecies = [Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine,
Species.Musteline, Species.Procyon, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate,
Species.Anthro, Species.Bovine, Species.Caprinae, Species.Marsupial, Species.Hyaenidae, Species.Minotaur,
Species.Bat, Species.Mephitidae, Species.Taur, Species.Giraffe, Species.Rhinoceros];
export interface SpeciesMap {
[key: number]: string[];
}
export interface SpeciesStrMap {
[key: number]: string;
}
export const speciesNames: SpeciesStrMap = {
[Species.MarineMammal]: 'marine mammals',
[Species.Elf]: 'elves',
[Species.Fish]: 'fishes',
[Species.Mephitidae]: 'mephitis',
[Species.Rhinoceros]: 'rhinoceros'
};
export const speciesMapping: SpeciesMap = {
[Species.Human]: ['human', 'humanoid', 'angel', 'android', 'african american', 'africanamerican', 'woman', 'dothraki', 'homo sapien', 'homosapien', 'homosapian', 'hooman', 'hoomin', 'hooomin'],
[Species.Humanoid]: ['satyr', 'gnome', 'dwarf', 'halfling', 'tiefling', 'humanoid'],
[Species.Equine]: ['horse', 'stallion', 'mare', 'filly', 'equine', 'shire', 'donkey', 'mule', 'zebra', 'pony', 'unicorn', 'clydesdale', 'shire',
'appaloosa', 'friesian', 'draft', 'draught', 'alicorn', 'amazon', 'amazonian', 'horsie', 'hoss', 'pegasus', 'colt', 'filly'],
[Species.Feline]: ['cat', 'kitten', 'catgirl', 'neko', 'tiger', 'puma', 'lion', 'lioness',
'tigress', 'feline', 'jaguar', 'cheetah', 'lynx', 'leopard', 'cougar', 'kitty', 'migote', 'miqo\'te', 'miqote', 'ocelot',
'sabertooth', 'saber tooth', 'tabby', 'liger'],
[Species.Canine]: ['dog', 'wolf', 'dingo', 'coyote', 'jackal', 'canine', 'doberman', 'husky', 'hound', 'akita', 'pitbull', 'pit bull', 'terrier',
'bull terrier', 'australian shepherd', 'australian shepard', 'german shepherd', 'german shepard', 'malinois', 'woof', 'labrador', 'collie',
'canis', 'canid', 'chihuahua', 'poodle', 'chinchilla', 'chowchow', 'corgi', 'anubis', 'anubian', 'dalmatian', 'inumimi', 'lupine', 'malamute', 'mastiff',
'mutt', 'rottweiler', 'shih tzu', 'worgen'],
[Species.Vulpine]: ['fox', 'fennec', 'kitsune', 'vulpine', 'vixen'],
[Species.Avian]: ['bird', 'gryphon', 'phoenix', 'roc', 'chimera', 'avian', 'albatross', 'cockatiel', 'dove', 'eagle', 'owl', 'penguin', 'raven'],
[Species.Amphibian]: ['salamander', 'frog', 'toad', 'newt', 'amphibian'],
[Species.Cervine]: ['deer', 'elk', 'moose', 'cervid', 'cervine', 'caribou', 'reindeer', 'doe', 'stag'],
[Species.Insect]: ['bee', 'wasp', 'spider', 'scorpion', 'ant', 'insect'],
[Species.Lapine]: ['bunny', 'rabbit', 'hare', 'lapine'],
[Species.Dragon]: ['dragon', 'drake', 'wyvern', 'draconian'],
[Species.Demon]: ['demon', 'daemon', 'deamon', 'demoness', 'demonkin', 'devil', 'succubus', 'incubus', 'baphomet'],
[Species.Musteline]: ['mink', 'ferret', 'weasel', 'stoat', 'otter', 'wolverine', 'marten', 'musteline'],
[Species.Procyon]: ['raccoon', 'racoon', 'coatimund', 'longtail', 'procyon'],
[Species.Rodent]: ['rat', 'mouse', 'chipmunk', 'squirrel', 'rodent', 'maus'],
[Species.Ursine]: ['bear', 'panda', 'black bear', 'brown bear', 'polar bear', 'ursine'],
[Species.MarineMammal]: ['whale', 'killer whale', 'dolphin'],
[Species.Primate]: ['monkey', 'ape', 'chimp', 'chimpanzee', 'gorilla', 'lemur', 'silverback'],
[Species.Divinity]: ['god', 'goddess', 'demigod', 'demigoddess', 'demi-god', 'demi-goddess'],
[Species.Elf]: ['elf', 'e l f', 'drow', 'draenei', 'draenai', 'kaldorei', 'sindorei'],
[Species.Fish]: ['fish', 'shark', 'great white', 'sergal', 'elven'],
[Species.Orc]: ['orc'],
[Species.Reptile]: ['chameleon', 'anole', 'alligator', 'aligator', 'snake', 'crocodile', 'lizard', 'gator', 'gecko', 'reptile', 'reptilian'],
[Species.Anthro]: ['anthro', 'anthropomorphic'],
[Species.Bovine]: ['cow', 'bovine', 'bison', 'antelope', 'gazelle', 'oryx', 'black angus', 'bull', 'ox'],
[Species.Caprinae]: ['sheep', 'goat', 'ibex', 'takin', 'bharal', 'goral', 'serow', 'lamb'],
[Species.Marsupial]: ['opossum', 'possum', 'kangaroo', 'roo', 'koala', 'wombat'],
[Species.Hyaenidae]: ['hyena'],
[Species.Minotaur]: ['minotaur', 'tauren'],
[Species.Bat]: ['bat'],
[Species.Alien]: ['alien', 'krogan', 'xenomorph'],
[Species.Mephitidae]: ['skunk'],
[Species.Robot]: ['android', 'robot', 'cyborg'],
[Species.Dinosaur]: ['saurus', 'deathclaw', 'dinosaur', 'raptor', 'trex', 't-rex'],
[Species.Pokemon]: ['charizard', 'charmander', 'pikachu', 'digimon', 'renamon', 'eevee', 'gardevoir', 'absol', 'aggron', 'jolteon', 'lopunny'],
[Species.Fae]: ['fairy', 'fae', 'imp', 'elemental'],
[Species.Taur]: ['chakat', 'centaur', 'equitaur'],
[Species.Vampire]: ['vampyre', 'vampire', 'dhampir', 'daywalker'],
[Species.Naga]: ['naga', 'lamia'],
[Species.Monster]: ['gnoll', 'goblin', 'kobold', 'monster', 'troll', 'illithid', 'golem', 'basilisk'],
[Species.Giraffe]: ['giraffe'],
[Species.Rhinoceros]: ['rhino', 'rhinoceros']
};
export interface FchatGenderMap {
[key: string]: Gender;
}
export const fchatGenderMap: FchatGenderMap = {
None: Gender.None,
Male: Gender.Male,
Female: Gender.Female,
Shemale: Gender.Shemale,
Herm: Gender.Herm,
'Male-Herm': Gender.MaleHerm,
'Cunt-Boy': Gender.Cuntboy,
Transgender: Gender.Transgender
};
export interface KinkPreferenceMap {
[key: string]: KinkPreference;
}
export const kinkMapping: KinkPreferenceMap = {
favorite: KinkPreference.Favorite,
yes: KinkPreference.Yes,
maybe: KinkPreference.Maybe,
no: KinkPreference.No
};

View File

@ -1,275 +1,30 @@
/* eslint-disable no-null-keyword, max-file-line-count */
import * as _ from 'lodash';
import { Character, CharacterInfotag } from '../interfaces';
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
/* eslint-disable no-null-keyword */
import {
BodyType, fchatGenderMap,
FurryPreference,
Gender, genderKinkMapping,
Kink,
kinkMapping,
KinkPreference, mammalSpecies, nonAnthroSpecies,
Orientation,
Species, speciesMapping,
speciesNames,
SubDomRole,
TagId
} from './matcher-types';
export enum TagId {
Age = 1,
Orientation = 2,
Gender = 3,
Build = 13,
FurryPreference = 29,
SubDomRole = 15,
Position = 41,
BodyType = 51,
ApparentAge = 64,
RelationshipStatus = 42,
Species = 9,
LanguagePreference = 49
}
export enum Gender {
Male = 1,
Female = 2,
Transgender = 3,
Herm = 32,
MaleHerm = 51,
Cuntboy = 69,
None = 105,
Shemale = 141
}
export enum SubDomRole {
AlwaysSubmissive = 7,
UsuallySubmissive = 8,
Switch = 9,
UsuallyDominant = 10,
AlwaysDominant = 11
}
export enum Orientation {
Straight = 4,
Gay = 5,
Bisexual = 6,
Asexual = 7,
Unsure = 8,
BiMalePreference = 89,
BiFemalePreference = 90,
Pansexual = 127,
BiCurious = 128
}
export enum BodyType {
Anthro = 122,
Feral = 121,
Morphable = 123,
Varies = 124,
Other = 125,
Androgynous = 126,
Human = 143,
Taur = 145
}
export enum KinkPreference {
Favorite = 1,
Yes = 0.5,
Maybe = -0.5,
No = -1
}
enum Kink {
Females = 554,
MaleHerms = 552,
Males = 553,
Transgenders = 551,
Herms = 132,
Shemales = 356,
Cuntboys = 231,
OlderCharacters = 109,
YoungerCharacters = 197,
Ageplay = 196,
UnderageCharacters = 207,
RoleReversal = 408,
AnthroCharacters = 587,
Humans = 609,
Mammals = 224
}
export enum FurryPreference {
FurriesOnly = 39,
FursAndHumans = 40,
HumansOnly = 41,
HumansPreferredFurriesOk = 150,
FurriesPreferredHumansOk = 149
}
interface GenderKinkIdMap {
[key: number]: Kink
}
const genderKinkMapping: GenderKinkIdMap = {
[Gender.Female]: Kink.Females,
[Gender.Male]: Kink.Males,
[Gender.Cuntboy]: Kink.Cuntboys,
[Gender.Herm]: Kink.Herms,
[Gender.MaleHerm]: Kink.MaleHerms,
[Gender.Shemale]: Kink.Shemales,
[Gender.Transgender]: Kink.Transgenders
};
// if no species and 'no furry characters', === human
// if no species and dislike 'anthro characters' === human
export enum Species {
Human = 609,
Humanoid = 131,
Bovine = 318,
Equine = 236,
Feline = 212,
Canine = 226,
Caprinae = 558,
Demon = 7,
Divinity = 530,
Vulpine = 213,
Avian = 215,
Amphibian = 223,
Cervine = 227,
Insect = 237,
Lapine = 214,
Musteline = 328,
Dragon = 228,
Procyon = 325,
Rodent = 283,
Ursine = 326,
MarineMammal = 309,
Primate = 613,
Elf = 611,
Orc = 615,
Fish = 608,
Reptile = 225,
Marsupial = 322,
Anthro = 587,
Robot = 161,
Hyaenidae = 321,
Mephitidae = 323,
Bat = 451,
Alien = 281,
Dinosaur = 610,
Pokemon = 504,
Fae = 612,
Taur = 68,
Vampire = 182,
Naga = 619,
Monster = 483,
Minotaur = 12121212,
Giraffe = 13131313,
Rhinoceros = 14141414
}
const nonAnthroSpecies = [
Species.Human, Species.Elf, Species.Orc, Species.Humanoid,
Species.Demon, Species.Divinity, Species.Alien, Species.Robot,
Species.Fae, Species.Vampire
];
const mammalSpecies = [Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine,
Species.Musteline, Species.Procyon, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate,
Species.Anthro, Species.Bovine, Species.Caprinae, Species.Marsupial, Species.Hyaenidae, Species.Minotaur,
Species.Bat, Species.Mephitidae, Species.Taur, Species.Giraffe, Species.Rhinoceros];
interface SpeciesMap {
[key: number]: string[];
}
interface SpeciesStrMap {
[key: number]: string;
}
export const speciesNames: SpeciesStrMap = {
[Species.MarineMammal]: 'marine mammals',
[Species.Elf]: 'elves',
[Species.Fish]: 'fishes',
[Species.Mephitidae]: 'mephitis',
[Species.Rhinoceros]: 'rhinoceros'
};
const speciesMapping: SpeciesMap = {
[Species.Human]: ['human', 'humanoid', 'angel', 'android', 'african american', 'africanamerican', 'woman', 'dothraki', 'homo sapien', 'homosapien', 'homosapian', 'hooman', 'hoomin', 'hooomin'],
[Species.Humanoid]: ['satyr', 'gnome', 'dwarf', 'halfling', 'tiefling', 'humanoid'],
[Species.Equine]: ['horse', 'stallion', 'mare', 'filly', 'equine', 'shire', 'donkey', 'mule', 'zebra', 'pony', 'unicorn', 'clydesdale', 'shire',
'appaloosa', 'friesian', 'draft', 'draught', 'alicorn', 'amazon', 'amazonian', 'horsie', 'hoss', 'pegasus', 'colt', 'filly'],
[Species.Feline]: ['cat', 'kitten', 'catgirl', 'neko', 'tiger', 'puma', 'lion', 'lioness',
'tigress', 'feline', 'jaguar', 'cheetah', 'lynx', 'leopard', 'cougar', 'kitty', 'migote', 'miqo\'te', 'miqote', 'ocelot',
'sabertooth', 'saber tooth', 'tabby', 'liger'],
[Species.Canine]: ['dog', 'wolf', 'dingo', 'coyote', 'jackal', 'canine', 'doberman', 'husky', 'hound', 'akita', 'pitbull', 'pit bull', 'terrier',
'bull terrier', 'australian shepherd', 'australian shepard', 'german shepherd', 'german shepard', 'malinois', 'woof', 'labrador', 'collie',
'canis', 'canid', 'chihuahua', 'poodle', 'chinchilla', 'chowchow', 'corgi', 'anubis', 'anubian', 'dalmatian', 'inumimi', 'lupine', 'malamute', 'mastiff',
'mutt', 'rottweiler', 'shih tzu', 'worgen'],
[Species.Vulpine]: ['fox', 'fennec', 'kitsune', 'vulpine', 'vixen'],
[Species.Avian]: ['bird', 'gryphon', 'phoenix', 'roc', 'chimera', 'avian', 'albatross', 'cockatiel', 'dove', 'eagle', 'owl', 'penguin', 'raven'],
[Species.Amphibian]: ['salamander', 'frog', 'toad', 'newt', 'amphibian'],
[Species.Cervine]: ['deer', 'elk', 'moose', 'cervid', 'cervine', 'caribou', 'reindeer', 'doe', 'stag'],
[Species.Insect]: ['bee', 'wasp', 'spider', 'scorpion', 'ant', 'insect'],
[Species.Lapine]: ['bunny', 'rabbit', 'hare', 'lapine'],
[Species.Dragon]: ['dragon', 'drake', 'wyvern', 'draconian'],
[Species.Demon]: ['demon', 'daemon', 'deamon', 'demoness', 'demonkin', 'devil', 'succubus', 'incubus', 'baphomet'],
[Species.Musteline]: ['mink', 'ferret', 'weasel', 'stoat', 'otter', 'wolverine', 'marten', 'musteline'],
[Species.Procyon]: ['raccoon', 'racoon', 'coatimund', 'longtail', 'procyon'],
[Species.Rodent]: ['rat', 'mouse', 'chipmunk', 'squirrel', 'rodent', 'maus'],
[Species.Ursine]: ['bear', 'panda', 'black bear', 'brown bear', 'polar bear', 'ursine'],
[Species.MarineMammal]: ['whale', 'killer whale', 'dolphin'],
[Species.Primate]: ['monkey', 'ape', 'chimp', 'chimpanzee', 'gorilla', 'lemur', 'silverback'],
[Species.Divinity]: ['god', 'goddess', 'demigod', 'demigoddess', 'demi-god', 'demi-goddess'],
[Species.Elf]: ['elf', 'e l f', 'drow', 'draenei', 'draenai', 'kaldorei', 'sindorei'],
[Species.Fish]: ['fish', 'shark', 'great white', 'sergal', 'elven'],
[Species.Orc]: ['orc'],
[Species.Reptile]: ['chameleon', 'anole', 'alligator', 'aligator', 'snake', 'crocodile', 'lizard', 'gator', 'gecko', 'reptile', 'reptilian'],
[Species.Anthro]: ['anthro', 'anthropomorphic'],
[Species.Bovine]: ['cow', 'bovine', 'bison', 'antelope', 'gazelle', 'oryx', 'black angus', 'bull', 'ox'],
[Species.Caprinae]: ['sheep', 'goat', 'ibex', 'takin', 'bharal', 'goral', 'serow', 'lamb'],
[Species.Marsupial]: ['opossum', 'possum', 'kangaroo', 'roo', 'koala', 'wombat'],
[Species.Hyaenidae]: ['hyena'],
[Species.Minotaur]: ['minotaur', 'tauren'],
[Species.Bat]: ['bat'],
[Species.Alien]: ['alien', 'krogan', 'xenomorph'],
[Species.Mephitidae]: ['skunk'],
[Species.Robot]: ['android', 'robot', 'cyborg'],
[Species.Dinosaur]: ['saurus', 'deathclaw', 'dinosaur', 'raptor', 'trex', 't-rex'],
[Species.Pokemon]: ['charizard', 'charmander', 'pikachu', 'digimon', 'renamon', 'eevee', 'gardevoir', 'absol', 'aggron', 'jolteon', 'lopunny'],
[Species.Fae]: ['fairy', 'fae', 'imp', 'elemental'],
[Species.Taur]: ['chakat', 'centaur', 'equitaur'],
[Species.Vampire]: ['vampyre', 'vampire', 'dhampir', 'daywalker'],
[Species.Naga]: ['naga', 'lamia'],
[Species.Monster]: ['gnoll', 'goblin', 'kobold', 'monster', 'troll', 'illithid', 'golem', 'basilisk'],
[Species.Giraffe]: ['giraffe'],
[Species.Rhinoceros]: ['rhino', 'rhinoceros']
};
interface FchatGenderMap {
[key: string]: Gender;
}
const fchatGenderMap: FchatGenderMap = {
None: Gender.None,
Male: Gender.Male,
Female: Gender.Female,
Shemale: Gender.Shemale,
Herm: Gender.Herm,
'Male-Herm': Gender.MaleHerm,
'Cunt-Boy': Gender.Cuntboy,
Transgender: Gender.Transgender
};
interface KinkPreferenceMap {
[key: string]: KinkPreference;
}
const kinkMapping: KinkPreferenceMap = {
favorite: KinkPreference.Favorite,
yes: KinkPreference.Yes,
maybe: KinkPreference.Maybe,
no: KinkPreference.No
};
export interface MatchReport {
you: MatchResult;
them: MatchResult;
youMultiSpecies: boolean;
themMultiSpecies: boolean;
score: Scoring | null;
}
export interface MatchResultCharacterInfo {
@ -339,6 +94,10 @@ export class Score {
}
}
export interface CharacterAnalysisVariation {
readonly character: Character;
readonly analysis: CharacterAnalysis;
}
export class CharacterAnalysis {
readonly character: Character;
@ -404,10 +163,139 @@ export class Matcher {
const youThem = new Matcher(you, them, yourAnalysis, theirAnalysis);
const themYou = new Matcher(them, you, theirAnalysis, yourAnalysis);
return {
const report: MatchReport = {
you: youThem.match(),
them: themYou.match()
them: themYou.match(),
youMultiSpecies: false,
themMultiSpecies: false,
score: null
};
report.score = Matcher.calculateReportScore(report);
return report;
}
static identifyBestMatchReport(you: Character, them: Character): MatchReport {
const reportStartTime = Date.now();
const yourCharacterAnalyses = Matcher.generateAnalysisVariations(you);
const theirCharacterAnalyses = Matcher.generateAnalysisVariations(them);
let bestScore = null;
let bestScoreLevelCount = 10000;
let bestReport: MatchReport;
for(const yourAnalysis of yourCharacterAnalyses) {
for (const theirAnalysis of theirCharacterAnalyses) {
const youThem = new Matcher(yourAnalysis.character, theirAnalysis.character, yourAnalysis.analysis, theirAnalysis.analysis);
const themYou = new Matcher(theirAnalysis.character, yourAnalysis.character, theirAnalysis.analysis, yourAnalysis.analysis);
const report: MatchReport = {
you: youThem.match(),
them: themYou.match(),
youMultiSpecies: (yourCharacterAnalyses.length > 1),
themMultiSpecies: (theirCharacterAnalyses.length > 1),
score: null
};
report.score = Matcher.calculateReportScore(report);
const scoreLevelCount = Matcher.countScoresAtLevel(report, report.score);
if (
(bestScore === null)
|| (
(report.score !== null)
&& (report.score >= bestScore)
&& (scoreLevelCount !== null)
&& (scoreLevelCount < bestScoreLevelCount)
)
) {
bestScore = report.score;
bestScoreLevelCount = (scoreLevelCount !== null) ? scoreLevelCount : 1000;
bestReport = report;
}
}
}
log.debug('report.identify.best', {buildTime: Date.now() - reportStartTime});
return bestReport!;
}
static generateAnalysisVariations(c: Character): CharacterAnalysisVariation[] {
const speciesOptions = Matcher.getAllSpeciesAsStr(c);
if (speciesOptions.length === 0) {
speciesOptions.push('');
}
return _.map(
speciesOptions,
(species) => {
const nc = _.cloneDeep(c);
nc.infotags[TagId.Species] = { string: species };
return { character: nc, analysis: new CharacterAnalysis(nc) };
}
);
}
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);
const finalScore = _.reduce(
_.concat(yourScores, theirScores),
(accum: Scoring | null, score: Score) => {
if (accum === null) {
return (score.score !== Scoring.NEUTRAL) ? score.score : null;
}
return (score.score === Scoring.NEUTRAL) ? accum : Math.min(accum, score.score);
},
null
);
if ((finalScore !== null) && (finalScore > 0)) {
// Manage edge cases where high score may not be ideal
// Nothing to score
if ((yourScores.length === 0) || (theirScores.length === 0)) {
// can't know
return Scoring.NEUTRAL;
}
// Only neutral scores given
if (
(_.every(yourScores, (n: Scoring) => n === Scoring.NEUTRAL)) ||
(_.every(theirScores, (n: Scoring) => n === Scoring.NEUTRAL))
) {
return Scoring.NEUTRAL;
}
}
// console.log('Profile score', c.character.name, score, m.you.total, m.them.total,
// m.you.total + m.them.total, m.you.total * m.them.total);
return (finalScore === null) ? Scoring.NEUTRAL : finalScore;
}
match(): MatchResult {
@ -850,16 +738,20 @@ export class Matcher {
}
static species(c: Character): Species | null {
let foundSpeciesId: Species | null = null;
let match = '';
const mySpecies = Matcher.getTagValue(TagId.Species, c);
if ((!mySpecies) || (!mySpecies.string)) {
return Species.Human; // best guess
}
const finalSpecies = mySpecies.string.toLowerCase();
return Matcher.getMappedSpecies(mySpecies.string);
}
static getMappedSpecies(species: string): Species | null {
let foundSpeciesId: Species | null = null;
let match = '';
const finalSpecies = species.toLowerCase().trim();
_.each(
speciesMapping,
@ -879,6 +771,23 @@ export class Matcher {
return foundSpeciesId;
}
static getAllSpecies(c: Character): Species[] {
const species = Matcher.getAllSpeciesAsStr(c);
return _.filter(_.map(species, (s) => Matcher.getMappedSpecies(s)), (s) => (s !== null)) as Species[];
}
static getAllSpeciesAsStr(c: Character): string[] {
const mySpecies = Matcher.getTagValue(TagId.Species, c);
if ((!mySpecies) || (!mySpecies.string)) {
return [];
}
const speciesStr = mySpecies.string.trim().toLowerCase().replace(/optionally|alternatively/g, ',').replace(/[)(]/g, '');
const matches = speciesStr.split(/[,]? or |,/);
return _.filter(_.map(matches, (m) => m.toLowerCase().trim()), (m) => (m !== ''));
}
static strToGender(fchatGenderStr: string | undefined): Gender | null {
if (fchatGenderStr === undefined) {

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, Score, Scoring } from './matcher';
import { Matcher, Scoring } from './matcher';
import { PermanentIndexedStore } from './store/sql-store';
import { CharacterImage, SimpleCharacter } from '../interfaces';
@ -175,52 +175,8 @@ export class ProfileCache extends AsyncCache<CharacterCacheRecord> {
return 0;
}
const m = Matcher.generateReport(you.character, c.character);
const m = Matcher.identifyBestMatchReport(you.character, c.character);
// let mul = Math.sign(Math.min(m.you.total, m.them.total));
// if (mul === 0)
// mul = 0.5;
// const score = Math.min(m.them.total, m.you.total); // mul * (Math.abs(m.you.total) + Math.abs(m.them.total));
const yourScores = _.values(m.you.scores);
const theirScores = _.values(m.them.scores);
const finalScore = _.reduce(
_.concat(yourScores, theirScores),
(accum: Scoring | null, score: Score) => {
if (accum === null) {
return (score.score !== Scoring.NEUTRAL) ? score.score : null;
}
return (score.score === Scoring.NEUTRAL) ? accum : Math.min(accum, score.score);
},
null
);
if ((finalScore !== null) && (finalScore > 0)) {
// Manage edge cases where high score may not be ideal
// Nothing to score
if ((yourScores.length === 0) || (theirScores.length === 0)) {
// can't know
return Scoring.NEUTRAL;
}
// Only neutral scores given
if (
(_.every(yourScores, (n: Scoring) => n === Scoring.NEUTRAL)) ||
(_.every(theirScores, (n: Scoring) => n === Scoring.NEUTRAL))
) {
return Scoring.NEUTRAL;
}
}
// console.log('Profile score', c.character.name, score, m.you.total, m.them.total,
// m.you.total + m.them.total, m.you.total * m.them.total);
return (finalScore === null) ? Scoring.NEUTRAL : finalScore;
return m.score === null ? Scoring.NEUTRAL : m.score;
}
}

View File

@ -2,9 +2,9 @@
// import * as path from 'path';
// import core from '../../chat/core';
import { Orientation, Gender, FurryPreference, Species } from '../matcher';
import {Character as ComplexCharacter, CharacterGroup, Guestbook} from '../../site/character_page/interfaces';
import { CharacterImage, SimpleCharacter } from '../../interfaces';
import { FurryPreference, Gender, Orientation, Species } from '../matcher-types';
// This design should be refactored; it's bad
export interface ProfileRecord {

View File

@ -428,7 +428,7 @@
if ((!this.selfCharacter) || (!this.character))
return;
this.characterMatch = Matcher.generateReport(this.selfCharacter.character, this.character.character);
this.characterMatch = Matcher.identifyBestMatchReport(this.selfCharacter.character, this.character.character);
// console.log('Match', this.selfCharacter.character.name, this.character.character.name, this.characterMatch);
}
@ -779,6 +779,12 @@
margin-left: 1rem;
}
.species {
display: inline-block;
color: var(--characterInfotagColor);
// opacity: 0.7;
}
ul {
padding: 0;
list-style: none;

View File

@ -14,8 +14,9 @@
import {formatContactLink, formatContactValue} from './contact_utils';
import {Store} from './data_store';
import {CONTACT_GROUP_ID} from './interfaces';
import { MatchReport, TagId } from '../../learn/matcher';
import { MatchReport } from '../../learn/matcher';
import { CssClassMap } from './match-report.vue';
import { TagId } from '../../learn/matcher-types';
@Component
export default class InfotagView extends Vue {

View File

@ -6,6 +6,7 @@
<h3>
<img :src="avatarUrl(characterMatch.you.you.name)" class="thumbnail"/>
{{characterMatch.you.you.name}}
<small v-if="characterMatch.youMultiSpecies" class="species">as {{getSpeciesStr(characterMatch.you)}}</small>
</h3>
<ul>
@ -21,6 +22,7 @@
<h3>
<img :src="avatarUrl(characterMatch.them.you.name)" class="thumbnail" />
{{characterMatch.them.you.name}}
<small v-if="characterMatch.themMultiSpecies" class="species">as {{getSpeciesStr(characterMatch.them)}}</small>
</h3>
<ul>
@ -35,8 +37,9 @@
import * as _ from 'lodash';
import Vue from 'vue';
import * as Utils from '../utils';
import { MatchReport, MatchResult, Score, Scoring } from '../../learn/matcher';
import { Matcher, MatchReport, MatchResult, Score, Scoring } from '../../learn/matcher';
import core from '../../chat/core';
import { TagId } from '../../learn/matcher-types';
export interface CssClassMap {
[key: string]: boolean;
@ -91,6 +94,12 @@
return _.map(result.scores, (s: Score) => (s));
}
getSpeciesStr(m: MatchResult): string {
const t = Matcher.getTagValue(TagId.Species, m.you);
return _.get(t, 'string', 'unknown');
}
async toggleMinimize(): Promise<void> {
this.isMinimized = !this.isMinimized;