<commit_before>/* eslint-disable import/default */
/* eslint-disable import/no-named-as-default-member */
import type {KnownBlock, ImageBlock, WebClient, ViewsOpenArguments} from '@slack/web-api';
import {Mutex} from 'async-mutex';
import type {Model} from 'ebisu-js';
import ebisu from 'ebisu-js';
import {sortBy, get, clamp} from 'lodash';
import schedule from 'node-schedule';
import type {SlackInterface} from '../lib/slack';
import {getMemberIcon, getMemberName, mrkdwn, plainText} from '../lib/slackUtils';
import State from '../lib/state';

interface Word {
	ja: string,
	en: string,
	createdAt: number,
}

type ChallengeWord = {
	en: string;
	forgettingRate: number,
	success: number;
};

interface Challenge {
	id: string,
	words: ChallengeWord[],
	createdAt: number,
	finished: boolean,
	participants: string[],
	ts: string,
}

interface StateObj {
	words: Word[],
	challenges: Challenge[],
}

const mutex = new Mutex();

class Dictionary {
	models: Map<string, Model>;

	words: Map<string, Word>;

	static t = 7 * 24 * 60 * 60 * 1000;

	constructor(words: Word[]) {
		this.models = new Map(words.map((word) => (
			[word.en, ebisu.defaultModel(Dictionary.t)]
		)));
		this.words = new Map(words.map((word) => (
			[word.en, word]
		)));
	}

	addWord(word: Word) {
		this.models.set(word.en, ebisu.defaultModel(Dictionary.t));
		this.words.set(word.en, word);
	}

	setRecall({word, success, total, now}: {word: string, success: number, total: number, now: number}) {
		const model = this.models.get(word);
		const wordData = this.words.get(word);

		if (!model || !wordData) {
			throw new Error(`${word} is not in the dictionary`);
		}

		const newModel = ebisu.updateRecall(model, success, total, now - wordData.createdAt);<commit_msg>remember-english: Update half-life of memory from 1 week to 1 month<commit_after>/* eslint-disable import/default */
/* eslint-disable import/no-named-as-default-member */
import type {KnownBlock, ImageBlock, WebClient, ViewsOpenArguments} from '@slack/web-api';
import {Mutex} from 'async-mutex';
import type {Model} from 'ebisu-js';
import ebisu from 'ebisu-js';
import {sortBy, get, clamp} from 'lodash';
import schedule from 'node-schedule';
import type {SlackInterface} from '../lib/slack';
import {getMemberIcon, getMemberName, mrkdwn, plainText} from '../lib/slackUtils';
import State from '../lib/state';

interface Word {
	ja: string,
	en: string,
	createdAt: number,
}

type ChallengeWord = {
	en: string;
	forgettingRate: number,
	success: number;
};

interface Challenge {
	id: string,
	words: ChallengeWord[],
	createdAt: number,
	finished: boolean,
	participants: string[],
	ts: string,
}

interface StateObj {
	words: Word[],
	challenges: Challenge[],
}

const mutex = new Mutex();

class Dictionary {
	models: Map<string, Model>;

	words: Map<string, Word>;

	static t = 30 * 24 * 60 * 60 * 1000;

	constructor(words: Word[]) {
		this.models = new Map(words.map((word) => (
			[word.en, ebisu.defaultModel(Dictionary.t)]
		)));
		this.words = new Map(words.map((word) => (
			[word.en, word]
		)));
	}

	addWord(word: Word) {
		this.models.set(word.en, ebisu.defaultModel(Dictionary.t));
		this.words.set(word.en, word);
	}

	setRecall({word, success, total, now}: {word: string, success: number, total: number, now: number}) {
		const model = this.models.get(word);
		const wordData = this.words.get(word);

		if (!model || !wordData) {
			throw new Error(`${word} is not in the dictionary`);
		}

		const newModel = ebisu.updateRecall(model, success, total, now - wordData.createdAt);
{'fraction_non_alphanumeric': 0.1575091575091575, 'fraction_numerical': 0.0070442378134685825, 'mean_word_length': 4.469953775038521, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1650371', 'n_tokens_mistral': 1291, 'n_tokens_neox': 1202, 'n_words': 331}