Virtual-Kimi / kimi-js /kimi-memory.js
VirtualKimi's picture
Upload 37 files
8c89f37 verified
// ===== KIMI MEMORY MANAGER =====
class KimiMemory {
constructor(database) {
this.db = database;
this.preferences = {
voiceRate: 1.1,
voicePitch: 1.1,
voiceVolume: 0.8,
lastInteraction: null,
totalInteractions: 0,
favoriteWords: [],
emotionalState: "neutral"
};
this.isReady = false;
// affectionTrait will be loaded from database during init()
this.affectionTrait = 50; // Temporary default until loaded from DB
}
async init() {
if (!this.db) {
console.warn("Database not available, using local mode");
return;
}
try {
this.selectedCharacter = await this.db.getSelectedCharacter();
// Start with lower favorability level - relationships must be built over time
this.favorabilityLevel = await this.db.getPreference(`favorabilityLevel_${this.selectedCharacter}`, 50);
// Load affection trait from personality database with coherent defaults
const charDefAff =
(window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[this.selectedCharacter]?.traits?.affection) || null;
const genericAff = (window.getTraitDefaults && window.getTraitDefaults().affection) || 55;
const defaultAff = typeof charDefAff === "number" ? charDefAff : genericAff;
this.affectionTrait = await this.db.getPersonalityTrait("affection", defaultAff, this.selectedCharacter);
this.preferences = {
voiceRate: await this.db.getPreference("voiceRate", 1.1),
voicePitch: await this.db.getPreference("voicePitch", 1.1),
voiceVolume: await this.db.getPreference("voiceVolume", 0.8),
lastInteraction: await this.db.getPreference(`lastInteraction_${this.selectedCharacter}`, null),
totalInteractions: await this.db.getPreference(`totalInteractions_${this.selectedCharacter}`, 0),
favoriteWords: await this.db.getPreference(`favoriteWords_${this.selectedCharacter}`, []),
emotionalState: await this.db.getPreference(`emotionalState_${this.selectedCharacter}`, "neutral")
};
// affectionTrait already loaded above with coherent default
this.isReady = true;
this.updateFavorabilityBar();
} catch (error) {
console.error("KimiMemory initialization error:", error);
}
}
async saveConversation(userText, kimiResponse, tokenInfo = null) {
if (!this.db) return;
try {
const character = await this.db.getSelectedCharacter();
await this.db.saveConversation(userText, kimiResponse, this.favorabilityLevel, new Date(), character);
// Legacy interactions counter kept for backward compatibility (not shown in UI now)
let total = await this.db.getPreference(`totalInteractions_${character}`, 0);
total = Number(total) + 1;
await this.db.setPreference(`totalInteractions_${character}`, total);
this.preferences.totalInteractions = total;
// Update tokens usage if provided (in/out)
if (tokenInfo && typeof tokenInfo.tokensIn === "number" && typeof tokenInfo.tokensOut === "number") {
const prevIn = Number(await this.db.getPreference(`totalTokensIn_${character}`, 0)) || 0;
const prevOut = Number(await this.db.getPreference(`totalTokensOut_${character}`, 0)) || 0;
await this.db.setPreference(`totalTokensIn_${character}`, prevIn + tokenInfo.tokensIn);
await this.db.setPreference(`totalTokensOut_${character}`, prevOut + tokenInfo.tokensOut);
}
let first = await this.db.getPreference(`firstInteraction_${character}`, null);
if (!first) {
first = new Date().toISOString();
await this.db.setPreference(`firstInteraction_${character}`, first);
}
this.preferences.lastInteraction = new Date().toISOString();
await this.db.setPreference(`lastInteraction_${character}`, this.preferences.lastInteraction);
} catch (error) {
console.error("Error saving conversation:", error);
}
}
async updateFavorability(change) {
try {
this.affectionTrait = Math.max(0, Math.min(100, this.affectionTrait + change));
if (this.db) {
await this.db.setPersonalityTrait("affection", this.affectionTrait, this.selectedCharacter);
}
this.updateFavorabilityBar();
} catch (error) {
console.error("Error updating favorability:", error);
}
}
async updateAffectionTrait() {
if (!this.db) return;
try {
this.selectedCharacter = await this.db.getSelectedCharacter();
// Use unified default that matches KimiEmotionSystem
this.affectionTrait = await this.db.getPersonalityTrait("affection", 50, this.selectedCharacter);
this.updateFavorabilityBar();
} catch (error) {
console.error("Error updating affection trait:", error);
}
}
updateFavorabilityBar() {
try {
const favorabilityBar = document.getElementById("favorability-bar");
const favorabilityText = document.getElementById("favorability-text");
const value = Number(this.affectionTrait) || 0;
const clamped = Math.max(0, Math.min(100, value));
if (favorabilityBar) {
favorabilityBar.style.width = `${clamped}%`;
}
if (favorabilityText) {
favorabilityText.textContent = `${clamped.toFixed(2)}%`;
}
} catch (error) {
console.error("Error updating favorability bar:", error);
}
}
getGreeting() {
const i18n = window.kimiI18nManager;
if (this.affectionTrait <= 10) {
return i18n?.t("greeting_low") || "Hello.";
}
if (this.affectionTrait < 40) {
return i18n?.t("greeting_mid") || "Hi. How can I help you?";
}
return i18n?.t("greeting_high") || "Hello my love! πŸ’•";
}
}
// Export to global scope
window.KimiMemory = KimiMemory;
export default KimiMemory;