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; | |