Spaces:
Running
Running
// ===== 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, | |
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(); | |
// Load affection trait from personality database with unified defaults | |
const charDefAff = | |
(window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[this.selectedCharacter]?.traits?.affection) || null; | |
const unifiedDefaults = window.kimiEmotionSystem?.TRAIT_DEFAULTS || { affection: 55 }; | |
const defaultAff = typeof charDefAff === "number" ? charDefAff : unifiedDefaults.affection; | |
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), | |
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(); | |
// Use global personality average for conversation favorability score | |
let relationshipLevel = 50; // fallback | |
try { | |
const traits = await this.db.getAllPersonalityTraits(character); | |
relationshipLevel = window.getPersonalityAverage ? window.getPersonalityAverage(traits) : 50; | |
} catch (error) { | |
console.warn("Error calculating relationship level for conversation:", error); | |
} | |
await this.db.saveConversation(userText, kimiResponse, relationshipLevel, 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 | |
const unifiedDefaults = window.kimiEmotionSystem?.TRAIT_DEFAULTS || { affection: 55 }; | |
this.affectionTrait = await this.db.getPersonalityTrait( | |
"affection", | |
unifiedDefaults.affection, | |
this.selectedCharacter | |
); | |
this.updateFavorabilityBar(); | |
} catch (error) { | |
console.error("Error updating affection trait:", error); | |
} | |
} | |
/** | |
* @deprecated Use updateGlobalPersonalityUI(). | |
* Thin wrapper retained for backward compatibility only. | |
*/ | |
updateFavorabilityBar() { | |
if (window.updateGlobalPersonalityUI) { | |
window.updateGlobalPersonalityUI(); | |
} | |
} | |
async getGreeting() { | |
const i18n = window.kimiI18nManager; | |
// Use global personality average instead of just affection trait | |
let relationshipLevel = 50; // fallback | |
try { | |
if (this.db) { | |
const traits = await this.db.getAllPersonalityTraits(this.selectedCharacter); | |
relationshipLevel = window.getPersonalityAverage ? window.getPersonalityAverage(traits) : 50; | |
} | |
} catch (error) { | |
console.warn("Error calculating greeting level:", error); | |
} | |
if (relationshipLevel <= 10) { | |
return i18n?.t("greeting_low") || "Hello."; | |
} | |
if (relationshipLevel < 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; | |