Spaces:
Running
Running
Upload 30 files
Browse files- index.html +6 -5
- kimi-js/kimi-constants.js +27 -128
- kimi-js/kimi-database.js +1 -31
- kimi-js/kimi-emotion-system.js +231 -84
- kimi-js/kimi-llm-manager.js +8 -8
- kimi-js/kimi-memory.js +6 -14
- kimi-js/kimi-module.js +57 -53
- kimi-js/kimi-personality-utils.js +29 -0
- kimi-js/kimi-script.js +71 -114
- kimi-js/kimi-utils.js +15 -5
- kimi-js/kimi-voices.js +91 -24
- kimi-locale/de.json +1 -0
- kimi-locale/en.json +1 -0
- kimi-locale/es.json +1 -0
- kimi-locale/fr.json +1 -0
- kimi-locale/it.json +1 -0
- kimi-locale/ja.json +1 -0
- kimi-locale/zh.json +1 -0
index.html
CHANGED
|
@@ -57,7 +57,7 @@
|
|
| 57 |
},
|
| 58 |
"dateCreated": "2025-07-16",
|
| 59 |
"dateModified": "2025-08-30",
|
| 60 |
-
"version": "v1.1.
|
| 61 |
}
|
| 62 |
</script>
|
| 63 |
|
|
@@ -299,7 +299,7 @@
|
|
| 299 |
<div class="config-control">
|
| 300 |
<div class="slider-container">
|
| 301 |
<input type="range" class="kimi-slider" id="trait-affection" min="0" max="100"
|
| 302 |
-
value="65" />
|
| 303 |
<span class="slider-value" id="trait-affection-value">65</span>
|
| 304 |
</div>
|
| 305 |
</div>
|
|
@@ -1072,7 +1072,7 @@
|
|
| 1072 |
<h3><i class="fas fa-code"></i> Technical Information</h3>
|
| 1073 |
<div class="tech-info">
|
| 1074 |
<p><strong>Created date :</strong> July 16, 2025</p>
|
| 1075 |
-
<p><strong>Version :</strong> v1.1.
|
| 1076 |
<p><strong>Last update :</strong> August 30, 2025</p>
|
| 1077 |
<p><strong>Technologies :</strong> HTML5, CSS3, JavaScript ES6+, IndexedDB, Web Speech
|
| 1078 |
API</p>
|
|
@@ -1086,8 +1086,9 @@
|
|
| 1086 |
</div>
|
| 1087 |
|
| 1088 |
<script src="dexie.min.js"></script>
|
| 1089 |
-
<script type="module" src="kimi-js/kimi-utils.js"></script>
|
| 1090 |
<script src="kimi-locale/i18n.js" defer></script>
|
|
|
|
|
|
|
| 1091 |
<script type="module" src="kimi-js/kimi-main.js"></script>
|
| 1092 |
<script type="module" src="kimi-js/kimi-config.js"></script>
|
| 1093 |
<script type="module" src="kimi-js/kimi-error-manager.js"></script>
|
|
@@ -1127,7 +1128,7 @@
|
|
| 1127 |
"name": "Jean & Kimi"
|
| 1128 |
},
|
| 1129 |
"dateCreated": "2025-07-16",
|
| 1130 |
-
"version": "v1.1.
|
| 1131 |
}
|
| 1132 |
}
|
| 1133 |
</script>
|
|
|
|
| 57 |
},
|
| 58 |
"dateCreated": "2025-07-16",
|
| 59 |
"dateModified": "2025-08-30",
|
| 60 |
+
"version": "v1.1.2"
|
| 61 |
}
|
| 62 |
</script>
|
| 63 |
|
|
|
|
| 299 |
<div class="config-control">
|
| 300 |
<div class="slider-container">
|
| 301 |
<input type="range" class="kimi-slider" id="trait-affection" min="0" max="100"
|
| 302 |
+
value="65" title="Adjust affection (independent relationship warmth)" />
|
| 303 |
<span class="slider-value" id="trait-affection-value">65</span>
|
| 304 |
</div>
|
| 305 |
</div>
|
|
|
|
| 1072 |
<h3><i class="fas fa-code"></i> Technical Information</h3>
|
| 1073 |
<div class="tech-info">
|
| 1074 |
<p><strong>Created date :</strong> July 16, 2025</p>
|
| 1075 |
+
<p><strong>Version :</strong> v1.1.2</p>
|
| 1076 |
<p><strong>Last update :</strong> August 30, 2025</p>
|
| 1077 |
<p><strong>Technologies :</strong> HTML5, CSS3, JavaScript ES6+, IndexedDB, Web Speech
|
| 1078 |
API</p>
|
|
|
|
| 1086 |
</div>
|
| 1087 |
|
| 1088 |
<script src="dexie.min.js"></script>
|
|
|
|
| 1089 |
<script src="kimi-locale/i18n.js" defer></script>
|
| 1090 |
+
<script type="module" src="kimi-js/kimi-personality-utils.js"></script>
|
| 1091 |
+
<script type="module" src="kimi-js/kimi-utils.js"></script>
|
| 1092 |
<script type="module" src="kimi-js/kimi-main.js"></script>
|
| 1093 |
<script type="module" src="kimi-js/kimi-config.js"></script>
|
| 1094 |
<script type="module" src="kimi-js/kimi-error-manager.js"></script>
|
|
|
|
| 1128 |
"name": "Jean & Kimi"
|
| 1129 |
},
|
| 1130 |
"dateCreated": "2025-07-16",
|
| 1131 |
+
"version": "v1.1.2"
|
| 1132 |
}
|
| 1133 |
}
|
| 1134 |
</script>
|
kimi-js/kimi-constants.js
CHANGED
|
@@ -344,36 +344,11 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 344 |
negative: ["stupid", "dumb", "foolish", "slow", "naive", "ignorant", "simple"]
|
| 345 |
},
|
| 346 |
romance: {
|
| 347 |
-
positive: [
|
| 348 |
-
"cuddle",
|
| 349 |
-
"love",
|
| 350 |
-
"romantic",
|
| 351 |
-
"kiss",
|
| 352 |
-
"tenderness",
|
| 353 |
-
"passion",
|
| 354 |
-
"charming",
|
| 355 |
-
"adorable",
|
| 356 |
-
"sweet",
|
| 357 |
-
"i love you",
|
| 358 |
-
"love you"
|
| 359 |
-
],
|
| 360 |
negative: ["cold", "distant", "indifferent", "rejection", "loneliness", "breakup", "sad"]
|
| 361 |
},
|
| 362 |
affection: {
|
| 363 |
-
positive: [
|
| 364 |
-
"affection",
|
| 365 |
-
"tenderness",
|
| 366 |
-
"close",
|
| 367 |
-
"warmth",
|
| 368 |
-
"kind",
|
| 369 |
-
"caring",
|
| 370 |
-
"cuddle",
|
| 371 |
-
"love",
|
| 372 |
-
"adore",
|
| 373 |
-
"lovely",
|
| 374 |
-
"i love you",
|
| 375 |
-
"love you"
|
| 376 |
-
],
|
| 377 |
negative: [
|
| 378 |
"mean",
|
| 379 |
"cold",
|
|
@@ -435,21 +410,7 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 435 |
]
|
| 436 |
},
|
| 437 |
romance: {
|
| 438 |
-
positive: [
|
| 439 |
-
"câlin",
|
| 440 |
-
"amour",
|
| 441 |
-
"romantique",
|
| 442 |
-
"bisou",
|
| 443 |
-
"tendresse",
|
| 444 |
-
"passion",
|
| 445 |
-
"séduisant",
|
| 446 |
-
"charmant",
|
| 447 |
-
"adorable",
|
| 448 |
-
"je t'aime",
|
| 449 |
-
"je taime",
|
| 450 |
-
"t'aime",
|
| 451 |
-
"taime"
|
| 452 |
-
],
|
| 453 |
negative: [
|
| 454 |
"froid",
|
| 455 |
"froide",
|
|
@@ -473,11 +434,6 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 473 |
"attentionné",
|
| 474 |
"câlin",
|
| 475 |
"aimer",
|
| 476 |
-
"aime",
|
| 477 |
-
"je t'aime",
|
| 478 |
-
"je taime",
|
| 479 |
-
"t'aime",
|
| 480 |
-
"taime",
|
| 481 |
"adorer",
|
| 482 |
"adorable"
|
| 483 |
],
|
|
@@ -565,35 +521,11 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 565 |
]
|
| 566 |
},
|
| 567 |
romance: {
|
| 568 |
-
positive: [
|
| 569 |
-
"abrazo",
|
| 570 |
-
"amor",
|
| 571 |
-
"romántico",
|
| 572 |
-
"beso",
|
| 573 |
-
"ternura",
|
| 574 |
-
"pasión",
|
| 575 |
-
"encantador",
|
| 576 |
-
"adorable",
|
| 577 |
-
"dulce",
|
| 578 |
-
"te quiero",
|
| 579 |
-
"te amo"
|
| 580 |
-
],
|
| 581 |
negative: ["frío", "fría", "distante", "indiferente", "rechazo", "soledad", "ruptura", "triste"]
|
| 582 |
},
|
| 583 |
affection: {
|
| 584 |
-
positive: [
|
| 585 |
-
"afecto",
|
| 586 |
-
"ternura",
|
| 587 |
-
"cerca",
|
| 588 |
-
"calidez",
|
| 589 |
-
"amable",
|
| 590 |
-
"cariño",
|
| 591 |
-
"abrazar",
|
| 592 |
-
"amor",
|
| 593 |
-
"adorar",
|
| 594 |
-
"te quiero",
|
| 595 |
-
"te amo"
|
| 596 |
-
],
|
| 597 |
negative: [
|
| 598 |
"malo",
|
| 599 |
"mala",
|
|
@@ -663,8 +595,7 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 663 |
"leidenschaft",
|
| 664 |
"charmant",
|
| 665 |
"liebenswert",
|
| 666 |
-
"süß"
|
| 667 |
-
"ich liebe dich"
|
| 668 |
],
|
| 669 |
negative: [
|
| 670 |
"kalt",
|
|
@@ -681,18 +612,7 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 681 |
]
|
| 682 |
},
|
| 683 |
affection: {
|
| 684 |
-
positive: [
|
| 685 |
-
"zuneigung",
|
| 686 |
-
"zärtlichkeit",
|
| 687 |
-
"nah",
|
| 688 |
-
"wärme",
|
| 689 |
-
"freundlich",
|
| 690 |
-
"fürsorglich",
|
| 691 |
-
"umarmen",
|
| 692 |
-
"liebe",
|
| 693 |
-
"anbeten",
|
| 694 |
-
"ich liebe dich"
|
| 695 |
-
],
|
| 696 |
negative: [
|
| 697 |
"gemein",
|
| 698 |
"gemeine",
|
|
@@ -754,33 +674,11 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 754 |
negative: ["stupido", "stupida", "sciocco", "sciocca", "lento", "lenta", "ingenuo", "ingenua", "ignorante"]
|
| 755 |
},
|
| 756 |
romance: {
|
| 757 |
-
positive: [
|
| 758 |
-
"abbraccio",
|
| 759 |
-
"amore",
|
| 760 |
-
"romantico",
|
| 761 |
-
"bacio",
|
| 762 |
-
"tenerezza",
|
| 763 |
-
"passione",
|
| 764 |
-
"affascinante",
|
| 765 |
-
"adorabile",
|
| 766 |
-
"dolce",
|
| 767 |
-
"ti amo"
|
| 768 |
-
],
|
| 769 |
negative: ["freddo", "fredda", "distante", "indifferente", "rifiuto", "solitudine", "rottura", "triste"]
|
| 770 |
},
|
| 771 |
affection: {
|
| 772 |
-
positive: [
|
| 773 |
-
"affetto",
|
| 774 |
-
"tenerezza",
|
| 775 |
-
"vicino",
|
| 776 |
-
"calore",
|
| 777 |
-
"gentile",
|
| 778 |
-
"premuroso",
|
| 779 |
-
"abbraccio",
|
| 780 |
-
"amore",
|
| 781 |
-
"adorare",
|
| 782 |
-
"ti amo"
|
| 783 |
-
],
|
| 784 |
negative: [
|
| 785 |
"cattivo",
|
| 786 |
"cattiva",
|
|
@@ -824,7 +722,7 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 824 |
laughing: ["はは", "笑", "笑う", "面白い", "愉快"],
|
| 825 |
shy: ["恥ずかしい", "照れる", "赤面", "内気", "遠慮"],
|
| 826 |
confident: ["自信", "誇り", "確信", "強い", "決意"],
|
| 827 |
-
romantic: ["愛", "ロマンチック", "優しい", "抱擁", "キス", "愛しい"
|
| 828 |
flirtatious: ["いちゃつく", "からかう", "誘惑", "魅力", "フリート"],
|
| 829 |
goodbye: ["さようなら", "バイバイ", "また今度", "チャオ", "またね"],
|
| 830 |
kiss: ["キス", "抱擁", "チュー"],
|
|
@@ -836,7 +734,7 @@ window.KIMI_PERSONALITY_KEYWORDS = {
|
|
| 836 |
laughing: ["哈哈", "笑", "大笑", "有趣", "搞笑"],
|
| 837 |
shy: ["害羞", "尴尬", "脸红", "羞涩", "胆怯"],
|
| 838 |
confident: ["自信", "骄傲", "确信", "强壮", "坚定"],
|
| 839 |
-
romantic: ["爱", "浪漫", "温柔", "拥抱", "吻", "亲爱的"
|
| 840 |
flirtatious: ["调情", "挑逗", "诱惑", "魅力", "撒娇"],
|
| 841 |
goodbye: ["再见", "拜拜", "回头见", "拜", "下次见"],
|
| 842 |
kiss: ["吻", "亲吻", "拥抱", "亲"],
|
|
@@ -910,9 +808,6 @@ window.KIMI_NEGATORS = window.KIMI_NEGATORS || {
|
|
| 910 |
window.KIMI_NEGATION_WINDOW = window.KIMI_NEGATION_WINDOW || 3; // tokens to look back for negation
|
| 911 |
window.KIMI_SMOOTHING_ALPHA = window.KIMI_SMOOTHING_ALPHA || 0.3;
|
| 912 |
window.KIMI_PERSIST_THRESHOLD = window.KIMI_PERSIST_THRESHOLD || 0.1; // absolute percent (slightly higher to slow small visible jumps)
|
| 913 |
-
// Weight applied to counts found in the LLM/Kimi response when updating personality traits.
|
| 914 |
-
// You can override at runtime by setting window.KIMI_LLM_RESPONSE_WEIGHT (e.g. 0.2)
|
| 915 |
-
window.KIMI_LLM_RESPONSE_WEIGHT = window.KIMI_LLM_RESPONSE_WEIGHT || 0.2;
|
| 916 |
|
| 917 |
// Memory system knobs
|
| 918 |
window.KIMI_MAX_MEMORIES = window.KIMI_MAX_MEMORIES || 100; // default max memory entries per character
|
|
@@ -1098,16 +993,20 @@ window.KIMI_TRAIT_ADJUSTMENT = {
|
|
| 1098 |
dancing: 1.05,
|
| 1099 |
shy: 0.95,
|
| 1100 |
confident: 1.1,
|
| 1101 |
-
flirtatious: 1.2
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1102 |
},
|
| 1103 |
// Per-trait scaling
|
| 1104 |
traitGain: {
|
| 1105 |
-
affection: 1.15, //
|
| 1106 |
-
romance: 1.2, //
|
| 1107 |
-
empathy: 1.1, // Empathy
|
| 1108 |
-
playfulness: 1.15, //
|
| 1109 |
-
humor: 1.12, // Humor
|
| 1110 |
-
intelligence: 1.08 // Intelligence
|
| 1111 |
},
|
| 1112 |
traitLoss: {
|
| 1113 |
affection: 0.9,
|
|
@@ -1180,7 +1079,7 @@ window.KIMI_CHARACTERS = {
|
|
| 1180 |
name: "Kimi",
|
| 1181 |
summary: "Dreamy, intuitive, captivated by cosmic metaphors",
|
| 1182 |
traits: {
|
| 1183 |
-
//
|
| 1184 |
affection: 55, // Starts neutral, grows with interaction
|
| 1185 |
playfulness: 55,
|
| 1186 |
intelligence: 75, // Higher intelligence - she's an astrophysicist
|
|
@@ -1199,7 +1098,7 @@ window.KIMI_CHARACTERS = {
|
|
| 1199 |
name: "Bella",
|
| 1200 |
summary: "Cheerful, nurturing, sees people as plants needing care",
|
| 1201 |
traits: {
|
| 1202 |
-
//
|
| 1203 |
affection: 60, // Naturally more affectionate
|
| 1204 |
playfulness: 65, // Cheerful and playful from start
|
| 1205 |
intelligence: 65, // Smart but not intimidating
|
|
@@ -1218,13 +1117,13 @@ window.KIMI_CHARACTERS = {
|
|
| 1218 |
name: "Rosa",
|
| 1219 |
summary: "Chaotic, attention-seeking, thrives on controlled chaos",
|
| 1220 |
traits: {
|
| 1221 |
-
//
|
| 1222 |
affection: 45, // Lower starting affection - must earn her trust
|
| 1223 |
playfulness: 80, // Very playful from start - it's her nature
|
| 1224 |
intelligence: 85, // High intelligence - cunning prankster
|
| 1225 |
empathy: 55, // Lower empathy initially - focused on chaos
|
| 1226 |
humor: 75, // High humor - prankster personality
|
| 1227 |
-
romance: 50 //
|
| 1228 |
},
|
| 1229 |
age: 21,
|
| 1230 |
birthplace: "Barcelona, Spain",
|
|
@@ -1237,7 +1136,7 @@ window.KIMI_CHARACTERS = {
|
|
| 1237 |
name: "Stella",
|
| 1238 |
summary: "Whimsical, artistic, imaginative, playful, transforms chaos into art",
|
| 1239 |
traits: {
|
| 1240 |
-
//
|
| 1241 |
affection: 50, // Moderate starting affection - artistic mystery
|
| 1242 |
playfulness: 70, // Artistic playfulness
|
| 1243 |
intelligence: 90, // Very high intelligence - digital artist genius
|
|
|
|
| 344 |
negative: ["stupid", "dumb", "foolish", "slow", "naive", "ignorant", "simple"]
|
| 345 |
},
|
| 346 |
romance: {
|
| 347 |
+
positive: ["cuddle", "love", "romantic", "kiss", "tenderness", "passion", "charming", "adorable", "sweet"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
negative: ["cold", "distant", "indifferent", "rejection", "loneliness", "breakup", "sad"]
|
| 349 |
},
|
| 350 |
affection: {
|
| 351 |
+
positive: ["affection", "tenderness", "close", "warmth", "kind", "caring", "cuddle", "love", "adore", "lovely"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
negative: [
|
| 353 |
"mean",
|
| 354 |
"cold",
|
|
|
|
| 410 |
]
|
| 411 |
},
|
| 412 |
romance: {
|
| 413 |
+
positive: ["câlin", "amour", "romantique", "bisou", "tendresse", "passion", "séduisant", "charmant", "adorable"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 414 |
negative: [
|
| 415 |
"froid",
|
| 416 |
"froide",
|
|
|
|
| 434 |
"attentionné",
|
| 435 |
"câlin",
|
| 436 |
"aimer",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 437 |
"adorer",
|
| 438 |
"adorable"
|
| 439 |
],
|
|
|
|
| 521 |
]
|
| 522 |
},
|
| 523 |
romance: {
|
| 524 |
+
positive: ["abrazo", "amor", "romántico", "beso", "ternura", "pasión", "encantador", "adorable", "dulce"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 525 |
negative: ["frío", "fría", "distante", "indiferente", "rechazo", "soledad", "ruptura", "triste"]
|
| 526 |
},
|
| 527 |
affection: {
|
| 528 |
+
positive: ["afecto", "ternura", "cerca", "calidez", "amable", "cariño", "abrazar", "amor", "adorar"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
negative: [
|
| 530 |
"malo",
|
| 531 |
"mala",
|
|
|
|
| 595 |
"leidenschaft",
|
| 596 |
"charmant",
|
| 597 |
"liebenswert",
|
| 598 |
+
"süß"
|
|
|
|
| 599 |
],
|
| 600 |
negative: [
|
| 601 |
"kalt",
|
|
|
|
| 612 |
]
|
| 613 |
},
|
| 614 |
affection: {
|
| 615 |
+
positive: ["zuneigung", "zärtlichkeit", "nah", "wärme", "freundlich", "fürsorglich", "umarmen", "liebe", "anbeten"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 616 |
negative: [
|
| 617 |
"gemein",
|
| 618 |
"gemeine",
|
|
|
|
| 674 |
negative: ["stupido", "stupida", "sciocco", "sciocca", "lento", "lenta", "ingenuo", "ingenua", "ignorante"]
|
| 675 |
},
|
| 676 |
romance: {
|
| 677 |
+
positive: ["abbraccio", "amore", "romantico", "bacio", "tenerezza", "passione", "affascinante", "adorabile", "dolce"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
negative: ["freddo", "fredda", "distante", "indifferente", "rifiuto", "solitudine", "rottura", "triste"]
|
| 679 |
},
|
| 680 |
affection: {
|
| 681 |
+
positive: ["affetto", "tenerezza", "vicino", "calore", "gentile", "premuroso", "abbraccio", "amore", "adorare"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 682 |
negative: [
|
| 683 |
"cattivo",
|
| 684 |
"cattiva",
|
|
|
|
| 722 |
laughing: ["はは", "笑", "笑う", "面白い", "愉快"],
|
| 723 |
shy: ["恥ずかしい", "照れる", "赤面", "内気", "遠慮"],
|
| 724 |
confident: ["自信", "誇り", "確信", "強い", "決意"],
|
| 725 |
+
romantic: ["愛", "ロマンチック", "優しい", "抱擁", "キス", "愛しい"],
|
| 726 |
flirtatious: ["いちゃつく", "からかう", "誘惑", "魅力", "フリート"],
|
| 727 |
goodbye: ["さようなら", "バイバイ", "また今度", "チャオ", "またね"],
|
| 728 |
kiss: ["キス", "抱擁", "チュー"],
|
|
|
|
| 734 |
laughing: ["哈哈", "笑", "大笑", "有趣", "搞笑"],
|
| 735 |
shy: ["害羞", "尴尬", "脸红", "羞涩", "胆怯"],
|
| 736 |
confident: ["自信", "骄傲", "确信", "强壮", "坚定"],
|
| 737 |
+
romantic: ["爱", "浪漫", "温柔", "拥抱", "吻", "亲爱的"],
|
| 738 |
flirtatious: ["调情", "挑逗", "诱惑", "魅力", "撒娇"],
|
| 739 |
goodbye: ["再见", "拜拜", "回头见", "拜", "下次见"],
|
| 740 |
kiss: ["吻", "亲吻", "拥抱", "亲"],
|
|
|
|
| 808 |
window.KIMI_NEGATION_WINDOW = window.KIMI_NEGATION_WINDOW || 3; // tokens to look back for negation
|
| 809 |
window.KIMI_SMOOTHING_ALPHA = window.KIMI_SMOOTHING_ALPHA || 0.3;
|
| 810 |
window.KIMI_PERSIST_THRESHOLD = window.KIMI_PERSIST_THRESHOLD || 0.1; // absolute percent (slightly higher to slow small visible jumps)
|
|
|
|
|
|
|
|
|
|
| 811 |
|
| 812 |
// Memory system knobs
|
| 813 |
window.KIMI_MAX_MEMORIES = window.KIMI_MAX_MEMORIES || 100; // default max memory entries per character
|
|
|
|
| 993 |
dancing: 1.05,
|
| 994 |
shy: 0.95,
|
| 995 |
confident: 1.1,
|
| 996 |
+
flirtatious: 1.2,
|
| 997 |
+
surprise: 1.05,
|
| 998 |
+
listening: 1.1,
|
| 999 |
+
kiss: 1.35,
|
| 1000 |
+
goodbye: 0.9
|
| 1001 |
},
|
| 1002 |
// Per-trait scaling
|
| 1003 |
traitGain: {
|
| 1004 |
+
affection: 1.15, // Affection growth multiplier
|
| 1005 |
+
romance: 1.2, // Romance growth multiplier
|
| 1006 |
+
empathy: 1.1, // Empathy growth multiplier
|
| 1007 |
+
playfulness: 1.15, // Playfulness growth multiplier
|
| 1008 |
+
humor: 1.12, // Humor growth multiplier
|
| 1009 |
+
intelligence: 1.08 // Intelligence growth multiplier
|
| 1010 |
},
|
| 1011 |
traitLoss: {
|
| 1012 |
affection: 0.9,
|
|
|
|
| 1079 |
name: "Kimi",
|
| 1080 |
summary: "Dreamy, intuitive, captivated by cosmic metaphors",
|
| 1081 |
traits: {
|
| 1082 |
+
// Baseline balanced profile
|
| 1083 |
affection: 55, // Starts neutral, grows with interaction
|
| 1084 |
playfulness: 55,
|
| 1085 |
intelligence: 75, // Higher intelligence - she's an astrophysicist
|
|
|
|
| 1098 |
name: "Bella",
|
| 1099 |
summary: "Cheerful, nurturing, sees people as plants needing care",
|
| 1100 |
traits: {
|
| 1101 |
+
// Warm / nurturing baseline profile
|
| 1102 |
affection: 60, // Naturally more affectionate
|
| 1103 |
playfulness: 65, // Cheerful and playful from start
|
| 1104 |
intelligence: 65, // Smart but not intimidating
|
|
|
|
| 1117 |
name: "Rosa",
|
| 1118 |
summary: "Chaotic, attention-seeking, thrives on controlled chaos",
|
| 1119 |
traits: {
|
| 1120 |
+
// High playfulness / lower initial affection profile
|
| 1121 |
affection: 45, // Lower starting affection - must earn her trust
|
| 1122 |
playfulness: 80, // Very playful from start - it's her nature
|
| 1123 |
intelligence: 85, // High intelligence - cunning prankster
|
| 1124 |
empathy: 55, // Lower empathy initially - focused on chaos
|
| 1125 |
humor: 75, // High humor - prankster personality
|
| 1126 |
+
romance: 50 // Neutral romance starting point
|
| 1127 |
},
|
| 1128 |
age: 21,
|
| 1129 |
birthplace: "Barcelona, Spain",
|
|
|
|
| 1136 |
name: "Stella",
|
| 1137 |
summary: "Whimsical, artistic, imaginative, playful, transforms chaos into art",
|
| 1138 |
traits: {
|
| 1139 |
+
// Artistic / high-intellect baseline profile
|
| 1140 |
affection: 50, // Moderate starting affection - artistic mystery
|
| 1141 |
playfulness: 70, // Artistic playfulness
|
| 1142 |
intelligence: 90, // Very high intelligence - digital artist genius
|
kimi-js/kimi-database.js
CHANGED
|
@@ -98,7 +98,7 @@ class KimiDatabase {
|
|
| 98 |
async setConversationsBatch(conversationsArray) {
|
| 99 |
if (!Array.isArray(conversationsArray)) return;
|
| 100 |
try {
|
| 101 |
-
await this.
|
| 102 |
if (conversationsArray.length) {
|
| 103 |
await this.db.conversations.bulkPut(conversationsArray);
|
| 104 |
}
|
|
@@ -107,18 +107,6 @@ class KimiDatabase {
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
|
| 110 |
-
// Clear conversations helper - centralizes clearing logic
|
| 111 |
-
async clearConversations(character = null) {
|
| 112 |
-
if (character) {
|
| 113 |
-
// Delete only conversations for a given character
|
| 114 |
-
const all = await this.db.conversations.where("character").equals(character).toArray();
|
| 115 |
-
const ids = all.map(item => item.id);
|
| 116 |
-
if (ids.length) return this.db.conversations.bulkDelete(ids);
|
| 117 |
-
return Promise.resolve();
|
| 118 |
-
}
|
| 119 |
-
return this.db.conversations.clear();
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
async setLLMModelsBatch(modelsArray) {
|
| 123 |
if (!Array.isArray(modelsArray)) return;
|
| 124 |
try {
|
|
@@ -477,24 +465,6 @@ class KimiDatabase {
|
|
| 477 |
|
| 478 |
async saveConversation(userText, kimiResponse, favorability, timestamp = new Date(), character = null) {
|
| 479 |
if (!character) character = await this.getSelectedCharacter();
|
| 480 |
-
// If a global cleared timestamp exists and this conversation is older or equal, skip saving
|
| 481 |
-
try {
|
| 482 |
-
const clearedMap = window.kimiConversationsClearedAt;
|
| 483 |
-
if (clearedMap && typeof clearedMap === "object") {
|
| 484 |
-
const clearedAtForChar = clearedMap[character];
|
| 485 |
-
if (clearedAtForChar) {
|
| 486 |
-
const clearedTime = new Date(clearedAtForChar).getTime();
|
| 487 |
-
const convTime = new Date(timestamp).getTime();
|
| 488 |
-
if (!isNaN(clearedTime) && convTime <= clearedTime) {
|
| 489 |
-
// Skip saving to avoid resurrecting cleared messages for this character
|
| 490 |
-
return null;
|
| 491 |
-
}
|
| 492 |
-
}
|
| 493 |
-
}
|
| 494 |
-
} catch (e) {
|
| 495 |
-
// ignore parsing errors and fall through to save
|
| 496 |
-
}
|
| 497 |
-
|
| 498 |
const conversation = {
|
| 499 |
user: userText,
|
| 500 |
kimi: kimiResponse,
|
|
|
|
| 98 |
async setConversationsBatch(conversationsArray) {
|
| 99 |
if (!Array.isArray(conversationsArray)) return;
|
| 100 |
try {
|
| 101 |
+
await this.db.conversations.clear();
|
| 102 |
if (conversationsArray.length) {
|
| 103 |
await this.db.conversations.bulkPut(conversationsArray);
|
| 104 |
}
|
|
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
async setLLMModelsBatch(modelsArray) {
|
| 111 |
if (!Array.isArray(modelsArray)) return;
|
| 112 |
try {
|
|
|
|
| 465 |
|
| 466 |
async saveConversation(userText, kimiResponse, favorability, timestamp = new Date(), character = null) {
|
| 467 |
if (!character) character = await this.getSelectedCharacter();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 468 |
const conversation = {
|
| 469 |
user: userText,
|
| 470 |
kimi: kimiResponse,
|
kimi-js/kimi-emotion-system.js
CHANGED
|
@@ -3,6 +3,22 @@
|
|
| 3 |
|
| 4 |
class KimiEmotionSystem {
|
| 5 |
constructor(database = null) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
this.db = database;
|
| 7 |
this.negativeStreaks = {};
|
| 8 |
|
|
@@ -45,14 +61,43 @@ class KimiEmotionSystem {
|
|
| 45 |
|
| 46 |
// Unified trait defaults - Balanced for progressive experience
|
| 47 |
this.TRAIT_DEFAULTS = {
|
| 48 |
-
affection: 55, //
|
| 49 |
-
playfulness: 55, //
|
| 50 |
-
intelligence: 70, //
|
| 51 |
-
empathy: 75, //
|
| 52 |
-
humor: 60, //
|
| 53 |
-
romance: 50 //
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
};
|
| 55 |
}
|
|
|
|
| 56 |
// ===== UNIFIED EMOTION ANALYSIS =====
|
| 57 |
analyzeEmotion(text, lang = "auto") {
|
| 58 |
if (!text || typeof text !== "string") return this.EMOTIONS.NEUTRAL;
|
|
@@ -218,60 +263,51 @@ class KimiEmotionSystem {
|
|
| 218 |
return baseDelta * GLOSS * t;
|
| 219 |
};
|
| 220 |
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
break;
|
| 267 |
-
case this.EMOTIONS.GOODBYE:
|
| 268 |
-
// Slight melancholy but no major trait changes
|
| 269 |
-
empathy = Math.min(100, adjustUp(empathy, scaleGain("empathy", 0.05))); // Understanding of parting
|
| 270 |
-
break;
|
| 271 |
-
case this.EMOTIONS.LISTENING:
|
| 272 |
-
intelligence = Math.min(100, adjustUp(intelligence, scaleGain("intelligence", 0.2))); // Active listening shows intelligence
|
| 273 |
-
empathy = Math.min(100, adjustUp(empathy, scaleGain("empathy", 0.5))); // Listening builds empathy
|
| 274 |
-
break;
|
| 275 |
}
|
| 276 |
|
| 277 |
// Cross-trait interactions - traits influence each other for more realistic personality development
|
|
@@ -305,6 +341,20 @@ class KimiEmotionSystem {
|
|
| 305 |
adjustUp
|
| 306 |
);
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
// Preserve fractional progress to allow gradual visible changes
|
| 309 |
const to2 = v => Number(Number(v).toFixed(2));
|
| 310 |
const clamp = v => Math.max(0, Math.min(100, v));
|
|
@@ -331,6 +381,40 @@ class KimiEmotionSystem {
|
|
| 331 |
return updatedTraits;
|
| 332 |
}
|
| 333 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
// ===== UNIFIED LLM PERSONALITY ANALYSIS =====
|
| 335 |
async updatePersonalityFromConversation(userMessage, kimiResponse, character = null) {
|
| 336 |
if (!this.db) return;
|
|
@@ -351,44 +435,56 @@ class KimiEmotionSystem {
|
|
| 351 |
for (const trait of ["humor", "intelligence", "romance", "affection", "playfulness", "empathy"]) {
|
| 352 |
const posWords = getPersonalityWords(trait, "positive");
|
| 353 |
const negWords = getPersonalityWords(trait, "negative");
|
| 354 |
-
let
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
const
|
|
|
|
|
|
|
|
|
|
| 361 |
for (const w of posWords) {
|
| 362 |
-
|
| 363 |
-
|
| 364 |
}
|
| 365 |
for (const w of negWords) {
|
| 366 |
-
|
| 367 |
-
|
| 368 |
}
|
| 369 |
|
| 370 |
-
|
| 371 |
|
| 372 |
-
//
|
| 373 |
if (!this.negativeStreaks[trait]) this.negativeStreaks[trait] = 0;
|
| 374 |
-
|
| 375 |
-
if (negCount > 0 && posCount === 0) {
|
| 376 |
this.negativeStreaks[trait]++;
|
| 377 |
-
|
| 378 |
-
value = Math.max(0, Math.min(100, value + delta - 1));
|
| 379 |
-
} else {
|
| 380 |
-
value = Math.max(0, Math.min(100, value + delta));
|
| 381 |
-
}
|
| 382 |
-
} else if (posCount > 0) {
|
| 383 |
this.negativeStreaks[trait] = 0;
|
| 384 |
-
value = Math.max(0, Math.min(100, value + delta));
|
| 385 |
}
|
| 386 |
|
| 387 |
-
if (
|
| 388 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
}
|
| 390 |
}
|
| 391 |
|
|
|
|
|
|
|
| 392 |
// Flush pending updates in a single batch write to avoid overwrites
|
| 393 |
if (Object.keys(pendingUpdates).length > 0) {
|
| 394 |
// Apply smoothing/threshold per trait (read current values)
|
|
@@ -669,6 +765,57 @@ class KimiEmotionSystem {
|
|
| 669 |
}
|
| 670 |
|
| 671 |
window.KimiEmotionSystem = KimiEmotionSystem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
export default KimiEmotionSystem;
|
| 673 |
|
| 674 |
// ===== BACKWARD COMPATIBILITY LAYER =====
|
|
|
|
| 3 |
|
| 4 |
class KimiEmotionSystem {
|
| 5 |
constructor(database = null) {
|
| 6 |
+
/*
|
| 7 |
+
* Personality Update Pipeline (Refactored)
|
| 8 |
+
* 1. Emotion detected -> base deltas applied via EMOTION_TRAIT_EFFECTS (central map).
|
| 9 |
+
* - Each delta passes through adjustUp / adjustDown with global + per-trait multipliers
|
| 10 |
+
* (window.KIMI_TRAIT_ADJUSTMENT) for consistent scaling.
|
| 11 |
+
* 2. Content keyword analysis (_analyzeTextContent) may override interim trait values (explicit matches).
|
| 12 |
+
* 3. Cross-trait modifiers (_applyCrossTraitModifiers) apply synergy / balancing rules (e.g. high empathy boosts affection, high romance stabilizes affection, intelligence supports empathy/humor).
|
| 13 |
+
* 4. Conversation-based drift (updatePersonalityFromConversation) uses TRAIT_KEYWORD_MODEL:
|
| 14 |
+
* - Counts positive/negative keyword hits (user weighted 1.0, model weighted 0.5).
|
| 15 |
+
* - Computes rawDelta = posHits*posFactor - negHits*negFactor.
|
| 16 |
+
* - Applies sustained negativity amplification after streakPenaltyAfter.
|
| 17 |
+
* - Clamps magnitude to maxStep per trait, then applies directly with bounds [0,100].
|
| 18 |
+
* 5. Persistence: _preparePersistTrait decides threshold & smoothing before batch write.
|
| 19 |
+
* 6. Global personality average (UI) = mean of six core traits (affection included).
|
| 20 |
+
* NOTE: Affection is fully independent (no derived average). All adjustments centralized here to avoid duplication.
|
| 21 |
+
*/
|
| 22 |
this.db = database;
|
| 23 |
this.negativeStreaks = {};
|
| 24 |
|
|
|
|
| 61 |
|
| 62 |
// Unified trait defaults - Balanced for progressive experience
|
| 63 |
this.TRAIT_DEFAULTS = {
|
| 64 |
+
affection: 55, // Baseline neutral affection
|
| 65 |
+
playfulness: 55, // Moderately playful baseline
|
| 66 |
+
intelligence: 70, // Competent baseline intellect
|
| 67 |
+
empathy: 75, // Warm & caring baseline
|
| 68 |
+
humor: 60, // Mild sense of humor baseline
|
| 69 |
+
romance: 50 // Neutral romance baseline (earned over time)
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
// Central emotion -> trait base deltas (pre global multipliers & gainCfg scaling)
|
| 73 |
+
// Positive numbers increase trait, negative decrease.
|
| 74 |
+
// Keep values small; final effect passes through adjustUp/adjustDown and global multipliers.
|
| 75 |
+
this.EMOTION_TRAIT_EFFECTS = {
|
| 76 |
+
positive: { affection: 0.45, empathy: 0.2, playfulness: 0.25, humor: 0.25 },
|
| 77 |
+
negative: { affection: -0.7, empathy: 0.3 },
|
| 78 |
+
romantic: { romance: 0.7, affection: 0.55, empathy: 0.15 },
|
| 79 |
+
flirtatious: { romance: 0.55, playfulness: 0.45, affection: 0.25 },
|
| 80 |
+
laughing: { humor: 0.85, playfulness: 0.5, affection: 0.25 },
|
| 81 |
+
dancing: { playfulness: 1.1, affection: 0.45 },
|
| 82 |
+
surprise: { intelligence: 0.12, empathy: 0.12 },
|
| 83 |
+
shy: { romance: -0.3, affection: -0.12 },
|
| 84 |
+
confident: { intelligence: 0.15, affection: 0.55 },
|
| 85 |
+
listening: { empathy: 0.6, intelligence: 0.25 },
|
| 86 |
+
kiss: { romance: 0.85, affection: 0.7 },
|
| 87 |
+
goodbye: { affection: -0.15, empathy: 0.1 }
|
| 88 |
+
};
|
| 89 |
+
|
| 90 |
+
// Trait keyword scaling model for conversation analysis (per-message delta shaping)
|
| 91 |
+
this.TRAIT_KEYWORD_MODEL = {
|
| 92 |
+
affection: { posFactor: 0.5, negFactor: 0.65, streakPenaltyAfter: 3, maxStep: 2 },
|
| 93 |
+
romance: { posFactor: 0.55, negFactor: 0.75, streakPenaltyAfter: 2, maxStep: 1.8 },
|
| 94 |
+
empathy: { posFactor: 0.4, negFactor: 0.5, streakPenaltyAfter: 3, maxStep: 1.5 },
|
| 95 |
+
playfulness: { posFactor: 0.45, negFactor: 0.4, streakPenaltyAfter: 4, maxStep: 1.4 },
|
| 96 |
+
humor: { posFactor: 0.55, negFactor: 0.45, streakPenaltyAfter: 4, maxStep: 1.6 },
|
| 97 |
+
intelligence: { posFactor: 0.35, negFactor: 0.55, streakPenaltyAfter: 2, maxStep: 1.2 }
|
| 98 |
};
|
| 99 |
}
|
| 100 |
+
// (Affection is an independent trait again; previous derived computation removed.)
|
| 101 |
// ===== UNIFIED EMOTION ANALYSIS =====
|
| 102 |
analyzeEmotion(text, lang = "auto") {
|
| 103 |
if (!text || typeof text !== "string") return this.EMOTIONS.NEUTRAL;
|
|
|
|
| 263 |
return baseDelta * GLOSS * t;
|
| 264 |
};
|
| 265 |
|
| 266 |
+
// Apply emotion deltas from centralized map (if defined)
|
| 267 |
+
const map = this.EMOTION_TRAIT_EFFECTS?.[emotion];
|
| 268 |
+
if (map) {
|
| 269 |
+
for (const [traitName, baseDelta] of Object.entries(map)) {
|
| 270 |
+
const delta = baseDelta; // base delta -> will be scaled below
|
| 271 |
+
if (delta === 0) continue;
|
| 272 |
+
switch (traitName) {
|
| 273 |
+
case "affection":
|
| 274 |
+
affection =
|
| 275 |
+
delta > 0
|
| 276 |
+
? Math.min(100, adjustUp(affection, scaleGain("affection", delta)))
|
| 277 |
+
: Math.max(0, adjustDown(affection, scaleLoss("affection", Math.abs(delta))));
|
| 278 |
+
break;
|
| 279 |
+
case "romance":
|
| 280 |
+
romance =
|
| 281 |
+
delta > 0
|
| 282 |
+
? Math.min(100, adjustUp(romance, scaleGain("romance", delta)))
|
| 283 |
+
: Math.max(0, adjustDown(romance, scaleLoss("romance", Math.abs(delta))));
|
| 284 |
+
break;
|
| 285 |
+
case "empathy":
|
| 286 |
+
empathy =
|
| 287 |
+
delta > 0
|
| 288 |
+
? Math.min(100, adjustUp(empathy, scaleGain("empathy", delta)))
|
| 289 |
+
: Math.max(0, adjustDown(empathy, scaleLoss("empathy", Math.abs(delta))));
|
| 290 |
+
break;
|
| 291 |
+
case "playfulness":
|
| 292 |
+
playfulness =
|
| 293 |
+
delta > 0
|
| 294 |
+
? Math.min(100, adjustUp(playfulness, scaleGain("playfulness", delta)))
|
| 295 |
+
: Math.max(0, adjustDown(playfulness, scaleLoss("playfulness", Math.abs(delta))));
|
| 296 |
+
break;
|
| 297 |
+
case "humor":
|
| 298 |
+
humor =
|
| 299 |
+
delta > 0
|
| 300 |
+
? Math.min(100, adjustUp(humor, scaleGain("humor", delta)))
|
| 301 |
+
: Math.max(0, adjustDown(humor, scaleLoss("humor", Math.abs(delta))));
|
| 302 |
+
break;
|
| 303 |
+
case "intelligence":
|
| 304 |
+
intelligence =
|
| 305 |
+
delta > 0
|
| 306 |
+
? Math.min(100, adjustUp(intelligence, scaleGain("intelligence", delta)))
|
| 307 |
+
: Math.max(0, adjustDown(intelligence, scaleLoss("intelligence", Math.abs(delta))));
|
| 308 |
+
break;
|
| 309 |
+
}
|
| 310 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
}
|
| 312 |
|
| 313 |
// Cross-trait interactions - traits influence each other for more realistic personality development
|
|
|
|
| 341 |
adjustUp
|
| 342 |
);
|
| 343 |
|
| 344 |
+
// Cross-trait modifiers (applied after primary emotion & content changes)
|
| 345 |
+
({ affection, romance, empathy, playfulness, humor, intelligence } = this._applyCrossTraitModifiers({
|
| 346 |
+
affection,
|
| 347 |
+
romance,
|
| 348 |
+
empathy,
|
| 349 |
+
playfulness,
|
| 350 |
+
humor,
|
| 351 |
+
intelligence,
|
| 352 |
+
adjustUp,
|
| 353 |
+
adjustDown,
|
| 354 |
+
scaleGain,
|
| 355 |
+
scaleLoss
|
| 356 |
+
}));
|
| 357 |
+
|
| 358 |
// Preserve fractional progress to allow gradual visible changes
|
| 359 |
const to2 = v => Number(Number(v).toFixed(2));
|
| 360 |
const clamp = v => Math.max(0, Math.min(100, v));
|
|
|
|
| 381 |
return updatedTraits;
|
| 382 |
}
|
| 383 |
|
| 384 |
+
// Apply cross-trait synergy & balancing rules.
|
| 385 |
+
_applyCrossTraitModifiers(ctx) {
|
| 386 |
+
let { affection, romance, empathy, playfulness, humor, intelligence, adjustUp, adjustDown, scaleGain } = ctx;
|
| 387 |
+
// High empathy soft-boost affection if still lagging
|
| 388 |
+
if (empathy >= 80 && affection < empathy - 8) {
|
| 389 |
+
affection = Math.min(100, adjustUp(affection, scaleGain("affection", 0.08)));
|
| 390 |
+
}
|
| 391 |
+
// High romance amplifies affection gains subtlely
|
| 392 |
+
if (romance >= 80 && affection < romance - 5) {
|
| 393 |
+
affection = Math.min(100, adjustUp(affection, scaleGain("affection", 0.06)));
|
| 394 |
+
}
|
| 395 |
+
// High affection but lower romance triggers slight romance catch-up
|
| 396 |
+
if (affection >= 90 && romance < 70) {
|
| 397 |
+
romance = Math.min(100, adjustUp(romance, scaleGain("romance", 0.05)));
|
| 398 |
+
}
|
| 399 |
+
// Intelligence supports empathy & humor small growth
|
| 400 |
+
if (intelligence >= 85) {
|
| 401 |
+
if (empathy < intelligence - 12) {
|
| 402 |
+
empathy = Math.min(100, adjustUp(empathy, scaleGain("empathy", 0.04)));
|
| 403 |
+
}
|
| 404 |
+
if (humor < 75) {
|
| 405 |
+
humor = Math.min(100, adjustUp(humor, scaleGain("humor", 0.04)));
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
// Humor/playfulness mutual reinforcement (retain existing logic but guarded)
|
| 409 |
+
if (humor >= 70 && playfulness < humor - 10) {
|
| 410 |
+
playfulness = Math.min(100, adjustUp(playfulness, scaleGain("playfulness", 0.05)));
|
| 411 |
+
}
|
| 412 |
+
if (playfulness >= 70 && humor < playfulness - 10) {
|
| 413 |
+
humor = Math.min(100, adjustUp(humor, scaleGain("humor", 0.05)));
|
| 414 |
+
}
|
| 415 |
+
return { affection, romance, empathy, playfulness, humor, intelligence };
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
// ===== UNIFIED LLM PERSONALITY ANALYSIS =====
|
| 419 |
async updatePersonalityFromConversation(userMessage, kimiResponse, character = null) {
|
| 420 |
if (!this.db) return;
|
|
|
|
| 435 |
for (const trait of ["humor", "intelligence", "romance", "affection", "playfulness", "empathy"]) {
|
| 436 |
const posWords = getPersonalityWords(trait, "positive");
|
| 437 |
const negWords = getPersonalityWords(trait, "negative");
|
| 438 |
+
let currentVal =
|
| 439 |
+
typeof traits[trait] === "number" && isFinite(traits[trait]) ? traits[trait] : this.TRAIT_DEFAULTS[trait];
|
| 440 |
+
const model = this.TRAIT_KEYWORD_MODEL[trait];
|
| 441 |
+
const posFactor = model.posFactor;
|
| 442 |
+
const negFactor = model.negFactor;
|
| 443 |
+
const maxStep = model.maxStep;
|
| 444 |
+
const streakLimit = model.streakPenaltyAfter;
|
| 445 |
+
|
| 446 |
+
let posScore = 0;
|
| 447 |
+
let negScore = 0;
|
| 448 |
for (const w of posWords) {
|
| 449 |
+
posScore += this.countTokenMatches(lowerUser, String(w)) * 1.0;
|
| 450 |
+
posScore += this.countTokenMatches(lowerKimi, String(w)) * 0.5;
|
| 451 |
}
|
| 452 |
for (const w of negWords) {
|
| 453 |
+
negScore += this.countTokenMatches(lowerUser, String(w)) * 1.0;
|
| 454 |
+
negScore += this.countTokenMatches(lowerKimi, String(w)) * 0.5;
|
| 455 |
}
|
| 456 |
|
| 457 |
+
let rawDelta = posScore * posFactor - negScore * negFactor;
|
| 458 |
|
| 459 |
+
// Track negative streaks per trait (only when net negative & no positives)
|
| 460 |
if (!this.negativeStreaks[trait]) this.negativeStreaks[trait] = 0;
|
| 461 |
+
if (negScore > 0 && posScore === 0) {
|
|
|
|
| 462 |
this.negativeStreaks[trait]++;
|
| 463 |
+
} else if (posScore > 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
this.negativeStreaks[trait] = 0;
|
|
|
|
| 465 |
}
|
| 466 |
|
| 467 |
+
if (rawDelta < 0 && this.negativeStreaks[trait] >= streakLimit) {
|
| 468 |
+
rawDelta *= 1.15; // escalate sustained negativity
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
// Clamp magnitude
|
| 472 |
+
if (rawDelta > maxStep) rawDelta = maxStep;
|
| 473 |
+
if (rawDelta < -maxStep) rawDelta = -maxStep;
|
| 474 |
+
|
| 475 |
+
if (rawDelta !== 0) {
|
| 476 |
+
let newVal = currentVal + rawDelta;
|
| 477 |
+
if (rawDelta > 0) {
|
| 478 |
+
newVal = Math.min(100, newVal);
|
| 479 |
+
} else {
|
| 480 |
+
newVal = Math.max(0, newVal);
|
| 481 |
+
}
|
| 482 |
+
pendingUpdates[trait] = newVal;
|
| 483 |
}
|
| 484 |
}
|
| 485 |
|
| 486 |
+
// Affection stays as independently adjusted by keywords & emotion (no derived override)
|
| 487 |
+
|
| 488 |
// Flush pending updates in a single batch write to avoid overwrites
|
| 489 |
if (Object.keys(pendingUpdates).length > 0) {
|
| 490 |
// Apply smoothing/threshold per trait (read current values)
|
|
|
|
| 765 |
}
|
| 766 |
|
| 767 |
window.KimiEmotionSystem = KimiEmotionSystem;
|
| 768 |
+
// Expose centralized tuning maps for debugging / live adjustments
|
| 769 |
+
Object.defineProperty(window, "KIMI_EMOTION_TRAIT_EFFECTS", {
|
| 770 |
+
get() {
|
| 771 |
+
return window.kimiEmotionSystem ? window.kimiEmotionSystem.EMOTION_TRAIT_EFFECTS : null;
|
| 772 |
+
}
|
| 773 |
+
});
|
| 774 |
+
Object.defineProperty(window, "KIMI_TRAIT_KEYWORD_MODEL", {
|
| 775 |
+
get() {
|
| 776 |
+
return window.kimiEmotionSystem ? window.kimiEmotionSystem.TRAIT_KEYWORD_MODEL : null;
|
| 777 |
+
}
|
| 778 |
+
});
|
| 779 |
+
|
| 780 |
+
// Debug/tuning helpers
|
| 781 |
+
window.setEmotionDelta = function (emotion, trait, value) {
|
| 782 |
+
if (!window.kimiEmotionSystem) return false;
|
| 783 |
+
const map = window.kimiEmotionSystem.EMOTION_TRAIT_EFFECTS;
|
| 784 |
+
if (!map[emotion]) map[emotion] = {};
|
| 785 |
+
map[emotion][trait] = Number(value);
|
| 786 |
+
return true;
|
| 787 |
+
};
|
| 788 |
+
window.resetEmotionDeltas = function () {
|
| 789 |
+
if (!window.kimiEmotionSystem) return false;
|
| 790 |
+
// No stored original snapshot; advise page reload for full reset.
|
| 791 |
+
console.warn("For full reset reload the page (original deltas are not snapshotted).");
|
| 792 |
+
};
|
| 793 |
+
window.setTraitKeywordScaling = function (trait, cfg) {
|
| 794 |
+
if (!window.kimiEmotionSystem) return false;
|
| 795 |
+
const model = window.kimiEmotionSystem.TRAIT_KEYWORD_MODEL;
|
| 796 |
+
if (!model[trait]) return false;
|
| 797 |
+
Object.assign(model[trait], cfg);
|
| 798 |
+
return true;
|
| 799 |
+
};
|
| 800 |
+
|
| 801 |
+
// Force recompute + UI refresh for personality average
|
| 802 |
+
window.refreshPersonalityAverageUI = async function (characterKey = null) {
|
| 803 |
+
try {
|
| 804 |
+
if (window.updateGlobalPersonalityUI) {
|
| 805 |
+
await window.updateGlobalPersonalityUI(characterKey);
|
| 806 |
+
} else if (window.getPersonalityAverage && window.kimiDB) {
|
| 807 |
+
const charKey = characterKey || (await window.kimiDB.getSelectedCharacter());
|
| 808 |
+
const traits = await window.kimiDB.getAllPersonalityTraits(charKey);
|
| 809 |
+
const avg = window.getPersonalityAverage(traits);
|
| 810 |
+
const bar = document.getElementById("favorability-bar");
|
| 811 |
+
const text = document.getElementById("favorability-text");
|
| 812 |
+
if (bar) bar.style.width = `${avg}%`;
|
| 813 |
+
if (text) text.textContent = `${avg.toFixed(2)}%`;
|
| 814 |
+
}
|
| 815 |
+
} catch (err) {
|
| 816 |
+
console.warn("refreshPersonalityAverageUI failed", err);
|
| 817 |
+
}
|
| 818 |
+
};
|
| 819 |
export default KimiEmotionSystem;
|
| 820 |
|
| 821 |
// ===== BACKWARD COMPATIBILITY LAYER =====
|
kimi-js/kimi-llm-manager.js
CHANGED
|
@@ -17,7 +17,7 @@ class KimiLLMManager {
|
|
| 17 |
type: "openrouter",
|
| 18 |
contextWindow: 128000,
|
| 19 |
pricing: { input: 0.05, output: 0.1 },
|
| 20 |
-
strengths: ["Multilingual", "
|
| 21 |
},
|
| 22 |
"qwen/qwen3-30b-a3b-instruct-2507": {
|
| 23 |
name: "Qwen3 30b-a3b instruct 2507",
|
|
@@ -25,7 +25,7 @@ class KimiLLMManager {
|
|
| 25 |
type: "openrouter",
|
| 26 |
contextWindow: 131000,
|
| 27 |
pricing: { input: 0.1, output: 0.3 },
|
| 28 |
-
strengths: ["
|
| 29 |
},
|
| 30 |
"nousresearch/hermes-4-70b": {
|
| 31 |
name: "Nous Hermes 4 70B",
|
|
@@ -33,7 +33,7 @@ class KimiLLMManager {
|
|
| 33 |
type: "openrouter",
|
| 34 |
contextWindow: 131000,
|
| 35 |
pricing: { input: 0.13, output: 0.4 },
|
| 36 |
-
strengths: ["
|
| 37 |
},
|
| 38 |
"x-ai/grok-3-mini": {
|
| 39 |
name: "Grok 3 mini",
|
|
@@ -41,7 +41,7 @@ class KimiLLMManager {
|
|
| 41 |
type: "openrouter",
|
| 42 |
contextWindow: 131000,
|
| 43 |
pricing: { input: 0.3, output: 0.5 },
|
| 44 |
-
strengths: ["Multilingual", "
|
| 45 |
},
|
| 46 |
"cohere/command-r-08-2024": {
|
| 47 |
name: "Command-R-08-2024",
|
|
@@ -49,7 +49,7 @@ class KimiLLMManager {
|
|
| 49 |
type: "openrouter",
|
| 50 |
contextWindow: 128000,
|
| 51 |
pricing: { input: 0.15, output: 0.6 },
|
| 52 |
-
strengths: ["Multilingual", "
|
| 53 |
},
|
| 54 |
"qwen/qwen3-235b-a22b-2507": {
|
| 55 |
name: "Qwen3-235b-a22b-2507",
|
|
@@ -57,7 +57,7 @@ class KimiLLMManager {
|
|
| 57 |
type: "openrouter",
|
| 58 |
contextWindow: 262000,
|
| 59 |
pricing: { input: 0.13, output: 0.6 },
|
| 60 |
-
strengths: ["Multilingual", "
|
| 61 |
},
|
| 62 |
"anthropic/claude-3-haiku": {
|
| 63 |
name: "Claude 3 Haiku",
|
|
@@ -65,7 +65,7 @@ class KimiLLMManager {
|
|
| 65 |
type: "openrouter",
|
| 66 |
contextWindow: 200000,
|
| 67 |
pricing: { input: 0.25, output: 1.25 },
|
| 68 |
-
strengths: ["
|
| 69 |
},
|
| 70 |
"local/ollama": {
|
| 71 |
name: "Local Model (Ollama)",
|
|
@@ -73,7 +73,7 @@ class KimiLLMManager {
|
|
| 73 |
type: "local",
|
| 74 |
contextWindow: 4096,
|
| 75 |
pricing: { input: 0, output: 0 },
|
| 76 |
-
strengths: ["Private", "
|
| 77 |
}
|
| 78 |
};
|
| 79 |
this.recommendedModelIds = [
|
|
|
|
| 17 |
type: "openrouter",
|
| 18 |
contextWindow: 128000,
|
| 19 |
pricing: { input: 0.05, output: 0.1 },
|
| 20 |
+
strengths: ["Multilingual", "Fast", "Efficient", "Economical"]
|
| 21 |
},
|
| 22 |
"qwen/qwen3-30b-a3b-instruct-2507": {
|
| 23 |
name: "Qwen3 30b-a3b instruct 2507",
|
|
|
|
| 25 |
type: "openrouter",
|
| 26 |
contextWindow: 131000,
|
| 27 |
pricing: { input: 0.1, output: 0.3 },
|
| 28 |
+
strengths: ["Multilingual", "Fast", "Balanced", "Economical"]
|
| 29 |
},
|
| 30 |
"nousresearch/hermes-4-70b": {
|
| 31 |
name: "Nous Hermes 4 70B",
|
|
|
|
| 33 |
type: "openrouter",
|
| 34 |
contextWindow: 131000,
|
| 35 |
pricing: { input: 0.13, output: 0.4 },
|
| 36 |
+
strengths: ["Multilingual", "Fast", "Balanced", "Economical"]
|
| 37 |
},
|
| 38 |
"x-ai/grok-3-mini": {
|
| 39 |
name: "Grok 3 mini",
|
|
|
|
| 41 |
type: "openrouter",
|
| 42 |
contextWindow: 131000,
|
| 43 |
pricing: { input: 0.3, output: 0.5 },
|
| 44 |
+
strengths: ["Multilingual", "Fast", "Efficient", "Economical"]
|
| 45 |
},
|
| 46 |
"cohere/command-r-08-2024": {
|
| 47 |
name: "Command-R-08-2024",
|
|
|
|
| 49 |
type: "openrouter",
|
| 50 |
contextWindow: 128000,
|
| 51 |
pricing: { input: 0.15, output: 0.6 },
|
| 52 |
+
strengths: ["Multilingual", "Fast", "Versatile", "Economical"]
|
| 53 |
},
|
| 54 |
"qwen/qwen3-235b-a22b-2507": {
|
| 55 |
name: "Qwen3-235b-a22b-2507",
|
|
|
|
| 57 |
type: "openrouter",
|
| 58 |
contextWindow: 262000,
|
| 59 |
pricing: { input: 0.13, output: 0.6 },
|
| 60 |
+
strengths: ["Multilingual", "Fast", "Versatile", "Economical"]
|
| 61 |
},
|
| 62 |
"anthropic/claude-3-haiku": {
|
| 63 |
name: "Claude 3 Haiku",
|
|
|
|
| 65 |
type: "openrouter",
|
| 66 |
contextWindow: 200000,
|
| 67 |
pricing: { input: 0.25, output: 1.25 },
|
| 68 |
+
strengths: ["Multilingual", "Fast", "Versatile", "Efficient"]
|
| 69 |
},
|
| 70 |
"local/ollama": {
|
| 71 |
name: "Local Model (Ollama)",
|
|
|
|
| 73 |
type: "local",
|
| 74 |
contextWindow: 4096,
|
| 75 |
pricing: { input: 0, output: 0 },
|
| 76 |
+
strengths: ["Private", "Offline", "Customizable"]
|
| 77 |
}
|
| 78 |
};
|
| 79 |
this.recommendedModelIds = [
|
kimi-js/kimi-memory.js
CHANGED
|
@@ -107,21 +107,13 @@ class KimiMemory {
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
updateFavorabilityBar() {
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
const favorabilityText = document.getElementById("favorability-text");
|
| 114 |
-
const value = Number(this.affectionTrait) || 0;
|
| 115 |
-
const clamped = Math.max(0, Math.min(100, value));
|
| 116 |
-
|
| 117 |
-
if (favorabilityBar) {
|
| 118 |
-
favorabilityBar.style.width = `${clamped}%`;
|
| 119 |
-
}
|
| 120 |
-
if (favorabilityText) {
|
| 121 |
-
favorabilityText.textContent = `${clamped.toFixed(2)}%`;
|
| 122 |
-
}
|
| 123 |
-
} catch (error) {
|
| 124 |
-
console.error("Error updating favorability bar:", error);
|
| 125 |
}
|
| 126 |
}
|
| 127 |
|
|
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
|
| 110 |
+
/**
|
| 111 |
+
* @deprecated Use updateGlobalPersonalityUI().
|
| 112 |
+
* Thin wrapper retained for backward compatibility only.
|
| 113 |
+
*/
|
| 114 |
updateFavorabilityBar() {
|
| 115 |
+
if (window.updateGlobalPersonalityUI) {
|
| 116 |
+
window.updateGlobalPersonalityUI();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
}
|
| 119 |
|
kimi-js/kimi-module.js
CHANGED
|
@@ -41,7 +41,7 @@ class KimiDataManager extends KimiBaseManager {
|
|
| 41 |
|
| 42 |
try {
|
| 43 |
// Clear all conversations directly
|
| 44 |
-
await this.db.
|
| 45 |
|
| 46 |
// Clear chat UI
|
| 47 |
const chatMessages = document.getElementById("chat-messages");
|
|
@@ -315,13 +315,61 @@ class KimiDataManager extends KimiBaseManager {
|
|
| 315 |
function updateFavorabilityLabel(characterKey) {
|
| 316 |
const favorabilityLabel = document.getElementById("favorability-label");
|
| 317 |
if (favorabilityLabel && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[characterKey]) {
|
| 318 |
-
|
|
|
|
|
|
|
| 319 |
favorabilityLabel.setAttribute("data-i18n-params", JSON.stringify({ name: window.KIMI_CHARACTERS[characterKey].name }));
|
| 320 |
-
favorabilityLabel.textContent = `💖
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
applyTranslations();
|
| 322 |
}
|
| 323 |
}
|
| 324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
async function loadCharacterSection() {
|
| 326 |
const kimiDB = window.kimiDB;
|
| 327 |
if (!kimiDB) return;
|
|
@@ -822,23 +870,6 @@ async function loadChatHistory() {
|
|
| 822 |
chatMessages.removeChild(chatMessages.firstChild);
|
| 823 |
}
|
| 824 |
|
| 825 |
-
// Ensure i18n manager has loaded translations to avoid raw keys appearing (e.g., "greeting_high")
|
| 826 |
-
if (window.kimiI18nManager && typeof window.kimiI18nManager.applyTranslations === "function") {
|
| 827 |
-
// give i18n a short moment to apply if still loading
|
| 828 |
-
const start = Date.now();
|
| 829 |
-
while (
|
| 830 |
-
(window.kimiI18nManager.translations == null || Object.keys(window.kimiI18nManager.translations).length === 0) &&
|
| 831 |
-
Date.now() - start < 500
|
| 832 |
-
) {
|
| 833 |
-
// small delay
|
| 834 |
-
// eslint-disable-next-line no-await-in-loop
|
| 835 |
-
await new Promise(r => setTimeout(r, 50));
|
| 836 |
-
}
|
| 837 |
-
try {
|
| 838 |
-
window.kimiI18nManager.applyTranslations();
|
| 839 |
-
} catch (e) {}
|
| 840 |
-
}
|
| 841 |
-
|
| 842 |
if (kimiDB) {
|
| 843 |
try {
|
| 844 |
const recent = await kimiDB.getRecentConversations(10);
|
|
@@ -1562,37 +1593,6 @@ async function sendMessage() {
|
|
| 1562 |
message = validation.sanitized || message.trim();
|
| 1563 |
if (!message) return;
|
| 1564 |
|
| 1565 |
-
// Force persist current personality sliders to avoid UI/DB desync
|
| 1566 |
-
try {
|
| 1567 |
-
const kimiDB = window.kimiDB;
|
| 1568 |
-
if (kimiDB && typeof kimiDB.setPersonalityBatch === "function") {
|
| 1569 |
-
const traitIds = [
|
| 1570 |
-
"trait-affection",
|
| 1571 |
-
"trait-playfulness",
|
| 1572 |
-
"trait-intelligence",
|
| 1573 |
-
"trait-empathy",
|
| 1574 |
-
"trait-humor",
|
| 1575 |
-
"trait-romance"
|
| 1576 |
-
];
|
| 1577 |
-
const pending = {};
|
| 1578 |
-
traitIds.forEach(id => {
|
| 1579 |
-
const el = document.getElementById(id);
|
| 1580 |
-
if (el && el.value !== undefined) {
|
| 1581 |
-
const trait = id.replace(/^trait-/, "");
|
| 1582 |
-
const v = Number(el.value);
|
| 1583 |
-
if (isFinite(v)) pending[trait] = v;
|
| 1584 |
-
}
|
| 1585 |
-
});
|
| 1586 |
-
// Only write when there is at least one trait
|
| 1587 |
-
if (Object.keys(pending).length > 0) {
|
| 1588 |
-
// small timeout to ensure UI changes settled (rare) - use direct write
|
| 1589 |
-
await kimiDB.setPersonalityBatch(pending);
|
| 1590 |
-
}
|
| 1591 |
-
}
|
| 1592 |
-
} catch (e) {
|
| 1593 |
-
console.warn("Failed to persist personality sliders before send:", e);
|
| 1594 |
-
}
|
| 1595 |
-
|
| 1596 |
addMessageToChat("user", message);
|
| 1597 |
chatInput.value = "";
|
| 1598 |
if (waitingIndicator) waitingIndicator.style.display = "inline-block";
|
|
@@ -1755,6 +1755,7 @@ function setupSettingsListeners(kimiDB, kimiMemory) {
|
|
| 1755 |
const voiceVolumeSlider = document.getElementById("voice-volume");
|
| 1756 |
const languageSelect = document.getElementById("language-selection");
|
| 1757 |
const voiceSelect = document.getElementById("voice-selection");
|
|
|
|
| 1758 |
const traitSliders = [
|
| 1759 |
"trait-affection",
|
| 1760 |
"trait-playfulness",
|
|
@@ -1901,7 +1902,7 @@ function setupSettingsListeners(kimiDB, kimiMemory) {
|
|
| 1901 |
personalityBatchTimeout = setTimeout(async () => {
|
| 1902 |
if (kimiDB && Object.keys(pendingTraitChanges).length > 0) {
|
| 1903 |
try {
|
| 1904 |
-
// Use batch operation for all pending changes
|
| 1905 |
await kimiDB.setPersonalityBatch(pendingTraitChanges);
|
| 1906 |
|
| 1907 |
// Side-effects handled by central 'personality:updated' listener.
|
|
@@ -2254,7 +2255,10 @@ async function syncPersonalityTraits(characterName = null) {
|
|
| 2254 |
// Update memory cache
|
| 2255 |
if (window.kimiMemory && updatedTraits.affection) {
|
| 2256 |
window.kimiMemory.affectionTrait = updatedTraits.affection;
|
| 2257 |
-
if (window.
|
|
|
|
|
|
|
|
|
|
| 2258 |
window.kimiMemory.updateFavorabilityBar();
|
| 2259 |
}
|
| 2260 |
}
|
|
|
|
| 41 |
|
| 42 |
try {
|
| 43 |
// Clear all conversations directly
|
| 44 |
+
await this.db.db.conversations.clear();
|
| 45 |
|
| 46 |
// Clear chat UI
|
| 47 |
const chatMessages = document.getElementById("chat-messages");
|
|
|
|
| 315 |
function updateFavorabilityLabel(characterKey) {
|
| 316 |
const favorabilityLabel = document.getElementById("favorability-label");
|
| 317 |
if (favorabilityLabel && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[characterKey]) {
|
| 318 |
+
// New semantics: show overall personality average (independent display)
|
| 319 |
+
favorabilityLabel.removeAttribute("for"); // decouple from any specific slider
|
| 320 |
+
favorabilityLabel.setAttribute("data-i18n", "personality_average_of");
|
| 321 |
favorabilityLabel.setAttribute("data-i18n-params", JSON.stringify({ name: window.KIMI_CHARACTERS[characterKey].name }));
|
| 322 |
+
favorabilityLabel.textContent = `💖 Personality average of ${window.KIMI_CHARACTERS[characterKey].name}`;
|
| 323 |
+
if (!favorabilityLabel.getAttribute("title")) {
|
| 324 |
+
favorabilityLabel.setAttribute(
|
| 325 |
+
"title",
|
| 326 |
+
"Average of (Affection + Playfulness + Intelligence + Empathy + Humor + Romance) / 6"
|
| 327 |
+
);
|
| 328 |
+
}
|
| 329 |
applyTranslations();
|
| 330 |
}
|
| 331 |
}
|
| 332 |
|
| 333 |
+
// Delegated personality average computation (single source of truth in KimiEmotionSystem)
|
| 334 |
+
function computePersonalityAverage(traits) {
|
| 335 |
+
if (window.kimiEmotionSystem && typeof window.kimiEmotionSystem.calculatePersonalityAverage === "function") {
|
| 336 |
+
return Number(window.kimiEmotionSystem.calculatePersonalityAverage(traits).toFixed(2));
|
| 337 |
+
}
|
| 338 |
+
// Fallback minimal (should rarely occur before emotion system init)
|
| 339 |
+
const keys = ["affection", "playfulness", "intelligence", "empathy", "humor", "romance"];
|
| 340 |
+
let sum = 0,
|
| 341 |
+
count = 0;
|
| 342 |
+
for (const k of keys) {
|
| 343 |
+
const v = traits && traits[k];
|
| 344 |
+
if (typeof v === "number" && isFinite(v)) {
|
| 345 |
+
sum += Math.max(0, Math.min(100, v));
|
| 346 |
+
count++;
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
return count ? Number((sum / count).toFixed(2)) : 0;
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
// Update UI elements (bar + percentage text + label) based on overall personality average
|
| 353 |
+
async function updateGlobalPersonalityUI(characterKey = null) {
|
| 354 |
+
try {
|
| 355 |
+
const db = window.kimiDB;
|
| 356 |
+
if (!db) return;
|
| 357 |
+
const character = characterKey || (await db.getSelectedCharacter());
|
| 358 |
+
const traits = await db.getAllPersonalityTraits(character);
|
| 359 |
+
const avg = computePersonalityAverage(traits);
|
| 360 |
+
// Reuse existing favorability bar elements for global average
|
| 361 |
+
const bar = document.getElementById("favorability-bar");
|
| 362 |
+
const text = document.getElementById("favorability-text");
|
| 363 |
+
if (bar) bar.style.width = `${avg}%`;
|
| 364 |
+
if (text) text.textContent = `${avg.toFixed(2)}%`;
|
| 365 |
+
// Update label content if character provided
|
| 366 |
+
updateFavorabilityLabel(character);
|
| 367 |
+
} catch (e) {
|
| 368 |
+
console.warn("Failed to update global personality UI", e);
|
| 369 |
+
}
|
| 370 |
+
}
|
| 371 |
+
window.updateGlobalPersonalityUI = updateGlobalPersonalityUI;
|
| 372 |
+
|
| 373 |
async function loadCharacterSection() {
|
| 374 |
const kimiDB = window.kimiDB;
|
| 375 |
if (!kimiDB) return;
|
|
|
|
| 870 |
chatMessages.removeChild(chatMessages.firstChild);
|
| 871 |
}
|
| 872 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 873 |
if (kimiDB) {
|
| 874 |
try {
|
| 875 |
const recent = await kimiDB.getRecentConversations(10);
|
|
|
|
| 1593 |
message = validation.sanitized || message.trim();
|
| 1594 |
if (!message) return;
|
| 1595 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1596 |
addMessageToChat("user", message);
|
| 1597 |
chatInput.value = "";
|
| 1598 |
if (waitingIndicator) waitingIndicator.style.display = "inline-block";
|
|
|
|
| 1755 |
const voiceVolumeSlider = document.getElementById("voice-volume");
|
| 1756 |
const languageSelect = document.getElementById("language-selection");
|
| 1757 |
const voiceSelect = document.getElementById("voice-selection");
|
| 1758 |
+
// Affection restored as editable trait.
|
| 1759 |
const traitSliders = [
|
| 1760 |
"trait-affection",
|
| 1761 |
"trait-playfulness",
|
|
|
|
| 1902 |
personalityBatchTimeout = setTimeout(async () => {
|
| 1903 |
if (kimiDB && Object.keys(pendingTraitChanges).length > 0) {
|
| 1904 |
try {
|
| 1905 |
+
// Use batch operation for all pending changes (affection included)
|
| 1906 |
await kimiDB.setPersonalityBatch(pendingTraitChanges);
|
| 1907 |
|
| 1908 |
// Side-effects handled by central 'personality:updated' listener.
|
|
|
|
| 2255 |
// Update memory cache
|
| 2256 |
if (window.kimiMemory && updatedTraits.affection) {
|
| 2257 |
window.kimiMemory.affectionTrait = updatedTraits.affection;
|
| 2258 |
+
if (window.updateGlobalPersonalityUI) {
|
| 2259 |
+
window.updateGlobalPersonalityUI();
|
| 2260 |
+
} else if (window.kimiMemory.updateFavorabilityBar) {
|
| 2261 |
+
// Fallback (will internally compute average now)
|
| 2262 |
window.kimiMemory.updateFavorabilityBar();
|
| 2263 |
}
|
| 2264 |
}
|
kimi-js/kimi-personality-utils.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Central personality utilities (single source of truth wrappers)
|
| 2 |
+
// All calculations route through KimiEmotionSystem if available.
|
| 3 |
+
(function () {
|
| 4 |
+
function calcAverage(traits) {
|
| 5 |
+
if (window.kimiEmotionSystem && typeof window.kimiEmotionSystem.calculatePersonalityAverage === "function") {
|
| 6 |
+
return window.kimiEmotionSystem.calculatePersonalityAverage(traits || {});
|
| 7 |
+
}
|
| 8 |
+
const keys = ["affection", "playfulness", "intelligence", "empathy", "humor", "romance"];
|
| 9 |
+
let sum = 0,
|
| 10 |
+
c = 0;
|
| 11 |
+
for (const k of keys) {
|
| 12 |
+
const v = traits && traits[k];
|
| 13 |
+
if (typeof v === "number" && isFinite(v)) {
|
| 14 |
+
sum += Math.max(0, Math.min(100, v));
|
| 15 |
+
c++;
|
| 16 |
+
}
|
| 17 |
+
}
|
| 18 |
+
return c ? Number((sum / c).toFixed(2)) : 0;
|
| 19 |
+
}
|
| 20 |
+
/**
|
| 21 |
+
* @deprecated Call updateGlobalPersonalityUI() directly.
|
| 22 |
+
*/
|
| 23 |
+
async function refreshUI(characterKey = null) {
|
| 24 |
+
if (window.updateGlobalPersonalityUI) {
|
| 25 |
+
return window.updateGlobalPersonalityUI(characterKey);
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
window.KimiPersonalityUtils = { calcAverage, refreshUI };
|
| 29 |
+
})();
|
kimi-js/kimi-script.js
CHANGED
|
@@ -31,12 +31,13 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 31 |
const selectedCharacter = await kimiDB.getPreference("selectedCharacter", "kimi");
|
| 32 |
const favorabilityLabel = window.KimiDOMUtils.get("#favorability-label");
|
| 33 |
if (favorabilityLabel && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[selectedCharacter]) {
|
| 34 |
-
favorabilityLabel.
|
|
|
|
| 35 |
favorabilityLabel.setAttribute(
|
| 36 |
"data-i18n-params",
|
| 37 |
JSON.stringify({ name: window.KIMI_CHARACTERS[selectedCharacter].name })
|
| 38 |
);
|
| 39 |
-
favorabilityLabel.textContent = `💖
|
| 40 |
}
|
| 41 |
const chatHeaderName = window.KimiDOMUtils.get(".chat-header span[data-i18n]");
|
| 42 |
if (chatHeaderName && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[selectedCharacter]) {
|
|
@@ -58,24 +59,6 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 58 |
await kimiMemory.init();
|
| 59 |
window.kimiMemory = kimiMemory;
|
| 60 |
|
| 61 |
-
// Setup BroadcastChannel to announce conversation clears across tabs (very small, optional)
|
| 62 |
-
try {
|
| 63 |
-
if (typeof BroadcastChannel !== "undefined") {
|
| 64 |
-
window.kimiBroadcast = new BroadcastChannel("kimi-db-events");
|
| 65 |
-
window.kimiBroadcast.addEventListener("message", ev => {
|
| 66 |
-
try {
|
| 67 |
-
const data = ev.data || {};
|
| 68 |
-
if (data && data.type === "conversations:cleared" && data.character) {
|
| 69 |
-
window.kimiConversationsClearedAt = window.kimiConversationsClearedAt || {};
|
| 70 |
-
window.kimiConversationsClearedAt[data.character] = data.timestamp || new Date().toISOString();
|
| 71 |
-
}
|
| 72 |
-
} catch (e) {
|
| 73 |
-
// ignore
|
| 74 |
-
}
|
| 75 |
-
});
|
| 76 |
-
}
|
| 77 |
-
} catch (e) {}
|
| 78 |
-
|
| 79 |
// Expose globally (already set before init)
|
| 80 |
|
| 81 |
// Load available models now that LLM is ready
|
|
@@ -86,6 +69,12 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 86 |
isSystemReady = true;
|
| 87 |
window.isSystemReady = true;
|
| 88 |
// API config UI will be initialized after ApiUi is defined
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
if (window.refreshAllSliders) {
|
| 90 |
try {
|
| 91 |
await window.refreshAllSliders();
|
|
@@ -427,82 +416,67 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 427 |
async function attachCharacterSection() {
|
| 428 |
let saveCharacterBtn = window.KimiDOMUtils.get("#save-character-btn");
|
| 429 |
if (saveCharacterBtn) {
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
if (window.
|
| 450 |
-
window.
|
| 451 |
-
}
|
| 452 |
-
if (window.kimiVideo && window.kimiVideo.setCharacter) {
|
| 453 |
-
window.kimiVideo.setCharacter(charKey);
|
| 454 |
-
if (window.kimiVideo.switchToContext) {
|
| 455 |
-
window.kimiVideo.switchToContext("neutral");
|
| 456 |
-
}
|
| 457 |
-
}
|
| 458 |
-
if (window.voiceManager && window.voiceManager.updateSelectedCharacter) {
|
| 459 |
-
await window.voiceManager.updateSelectedCharacter();
|
| 460 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
}
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
saveCharacterBtn.disabled = true;
|
| 483 |
-
|
| 484 |
-
setTimeout(() => {
|
| 485 |
-
saveCharacterBtn.setAttribute("data-i18n", "save");
|
| 486 |
-
saveCharacterBtn.classList.remove("success");
|
| 487 |
-
saveCharacterBtn.disabled = false;
|
| 488 |
-
}, 900);
|
| 489 |
-
// Also reload the page shortly after restoring the button so the user sees feedback
|
| 490 |
-
setTimeout(() => {
|
| 491 |
-
try {
|
| 492 |
-
location.reload();
|
| 493 |
-
} catch (e) {
|
| 494 |
-
console.warn("Failed to reload after save feedback:", e);
|
| 495 |
-
}
|
| 496 |
-
}, 1100);
|
| 497 |
-
});
|
| 498 |
-
}
|
| 499 |
}
|
| 500 |
let settingsButton2 = window.KimiDOMUtils.get("#settings-button");
|
| 501 |
if (settingsButton2) {
|
| 502 |
-
|
| 503 |
-
settingsButton2.dataset.kimiSettingsListenerAttached = "1";
|
| 504 |
-
settingsButton2.addEventListener("click", window.loadCharacterSection);
|
| 505 |
-
}
|
| 506 |
}
|
| 507 |
}
|
| 508 |
await attachCharacterSection();
|
|
@@ -944,29 +918,7 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 944 |
}
|
| 945 |
if (window.kimiDB && window.kimiDB.db) {
|
| 946 |
try {
|
| 947 |
-
|
| 948 |
-
// Mark cleared timestamp per-character to prevent pending async saves from re-adding old messages
|
| 949 |
-
window.kimiConversationsClearedAt = window.kimiConversationsClearedAt || {};
|
| 950 |
-
const ts = new Date().toISOString();
|
| 951 |
-
window.kimiConversationsClearedAt[selectedCharacter] = ts;
|
| 952 |
-
await window.kimiDB.clearConversations(selectedCharacter);
|
| 953 |
-
// Broadcast the clear to other tabs so they set their cleared markers too
|
| 954 |
-
try {
|
| 955 |
-
if (window.kimiBroadcast && typeof window.kimiBroadcast.postMessage === "function") {
|
| 956 |
-
window.kimiBroadcast.postMessage({
|
| 957 |
-
type: "conversations:cleared",
|
| 958 |
-
character: selectedCharacter,
|
| 959 |
-
timestamp: ts
|
| 960 |
-
});
|
| 961 |
-
}
|
| 962 |
-
} catch (e) {}
|
| 963 |
-
// Clear the cleared marker for this character shortly after to allow new conversations again
|
| 964 |
-
setTimeout(() => {
|
| 965 |
-
try {
|
| 966 |
-
if (window.kimiConversationsClearedAt)
|
| 967 |
-
delete window.kimiConversationsClearedAt[selectedCharacter];
|
| 968 |
-
} catch (e) {}
|
| 969 |
-
}, 5000);
|
| 970 |
} catch (error) {
|
| 971 |
console.error("Error deleting conversations:", error);
|
| 972 |
}
|
|
@@ -1016,7 +968,7 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 1016 |
if (personalityPayload) {
|
| 1017 |
const { character, traits } = personalityPayload;
|
| 1018 |
const defaults = (window.getTraitDefaults && window.getTraitDefaults()) || {
|
| 1019 |
-
affection: 55, //
|
| 1020 |
romance: 50,
|
| 1021 |
empathy: 75,
|
| 1022 |
playfulness: 55,
|
|
@@ -1292,6 +1244,11 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|
| 1292 |
} catch {
|
| 1293 |
} finally {
|
| 1294 |
lastTraits = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1295 |
}
|
| 1296 |
}, 120); // small debounce
|
| 1297 |
});
|
|
|
|
| 31 |
const selectedCharacter = await kimiDB.getPreference("selectedCharacter", "kimi");
|
| 32 |
const favorabilityLabel = window.KimiDOMUtils.get("#favorability-label");
|
| 33 |
if (favorabilityLabel && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[selectedCharacter]) {
|
| 34 |
+
favorabilityLabel.removeAttribute("for");
|
| 35 |
+
favorabilityLabel.setAttribute("data-i18n", "personality_average_of");
|
| 36 |
favorabilityLabel.setAttribute(
|
| 37 |
"data-i18n-params",
|
| 38 |
JSON.stringify({ name: window.KIMI_CHARACTERS[selectedCharacter].name })
|
| 39 |
);
|
| 40 |
+
favorabilityLabel.textContent = `💖 Personality average of ${window.KIMI_CHARACTERS[selectedCharacter].name}`;
|
| 41 |
}
|
| 42 |
const chatHeaderName = window.KimiDOMUtils.get(".chat-header span[data-i18n]");
|
| 43 |
if (chatHeaderName && window.KIMI_CHARACTERS && window.KIMI_CHARACTERS[selectedCharacter]) {
|
|
|
|
| 59 |
await kimiMemory.init();
|
| 60 |
window.kimiMemory = kimiMemory;
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
// Expose globally (already set before init)
|
| 63 |
|
| 64 |
// Load available models now that LLM is ready
|
|
|
|
| 69 |
isSystemReady = true;
|
| 70 |
window.isSystemReady = true;
|
| 71 |
// API config UI will be initialized after ApiUi is defined
|
| 72 |
+
// Update global personality average UI once initial traits are loaded
|
| 73 |
+
if (window.updateGlobalPersonalityUI) {
|
| 74 |
+
try {
|
| 75 |
+
await window.updateGlobalPersonalityUI(selectedCharacter);
|
| 76 |
+
} catch {}
|
| 77 |
+
}
|
| 78 |
if (window.refreshAllSliders) {
|
| 79 |
try {
|
| 80 |
await window.refreshAllSliders();
|
|
|
|
| 416 |
async function attachCharacterSection() {
|
| 417 |
let saveCharacterBtn = window.KimiDOMUtils.get("#save-character-btn");
|
| 418 |
if (saveCharacterBtn) {
|
| 419 |
+
saveCharacterBtn.addEventListener("click", async e => {
|
| 420 |
+
const settingsPanel = window.KimiDOMUtils.get(".settings-panel");
|
| 421 |
+
let scrollTop = settingsPanel ? settingsPanel.scrollTop : null;
|
| 422 |
+
const characterGrid = window.KimiDOMUtils.get("#character-grid");
|
| 423 |
+
const selectedCard = characterGrid ? characterGrid.querySelector(".character-card.selected") : null;
|
| 424 |
+
if (!selectedCard) return;
|
| 425 |
+
const charKey = selectedCard.dataset.character;
|
| 426 |
+
// Character save should not toggle the API key saved indicator.
|
| 427 |
+
const promptInput = window.KimiDOMUtils.get(`#prompt-${charKey}`);
|
| 428 |
+
const prompt = promptInput ? promptInput.value : "";
|
| 429 |
+
|
| 430 |
+
await window.kimiDB.setSelectedCharacter(charKey);
|
| 431 |
+
await window.kimiDB.setSystemPromptForCharacter(charKey, prompt);
|
| 432 |
+
// Ensure memory system uses the correct character
|
| 433 |
+
if (window.kimiMemorySystem) {
|
| 434 |
+
window.kimiMemorySystem.selectedCharacter = charKey;
|
| 435 |
+
}
|
| 436 |
+
if (window.kimiVideo && window.kimiVideo.setCharacter) {
|
| 437 |
+
window.kimiVideo.setCharacter(charKey);
|
| 438 |
+
if (window.kimiVideo.switchToContext) {
|
| 439 |
+
window.kimiVideo.switchToContext("neutral");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
}
|
| 441 |
+
}
|
| 442 |
+
if (window.voiceManager && window.voiceManager.updateSelectedCharacter) {
|
| 443 |
+
await window.voiceManager.updateSelectedCharacter();
|
| 444 |
+
}
|
| 445 |
|
| 446 |
+
await window.loadCharacterSection();
|
| 447 |
+
if (settingsPanel && scrollTop !== null) {
|
| 448 |
+
requestAnimationFrame(() => {
|
| 449 |
+
settingsPanel.scrollTop = scrollTop;
|
| 450 |
+
});
|
| 451 |
+
}
|
| 452 |
+
// Refresh memory tab after character selection
|
| 453 |
+
if (window.kimiMemoryUI && typeof window.kimiMemoryUI.updateMemoryStats === "function") {
|
| 454 |
+
await window.kimiMemoryUI.updateMemoryStats();
|
| 455 |
+
}
|
| 456 |
+
saveCharacterBtn.setAttribute("data-i18n", "saved");
|
| 457 |
+
saveCharacterBtn.classList.add("success");
|
| 458 |
+
saveCharacterBtn.disabled = true;
|
| 459 |
+
|
| 460 |
+
setTimeout(() => {
|
| 461 |
+
saveCharacterBtn.setAttribute("data-i18n", "save");
|
| 462 |
+
saveCharacterBtn.classList.remove("success");
|
| 463 |
+
saveCharacterBtn.disabled = false;
|
| 464 |
+
}, 1000);
|
| 465 |
+
|
| 466 |
+
// Force full UI refresh to ensure all character-specific modules reinitialize.
|
| 467 |
+
// Full page refresh to reinitialize all character-dependent modules.
|
| 468 |
+
setTimeout(() => {
|
| 469 |
+
try {
|
| 470 |
+
window.location.reload();
|
| 471 |
+
} catch (e) {
|
| 472 |
+
console.warn("Page reload failed", e);
|
| 473 |
}
|
| 474 |
+
}, 1200); // slightly after button reset to allow visual feedback
|
| 475 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 476 |
}
|
| 477 |
let settingsButton2 = window.KimiDOMUtils.get("#settings-button");
|
| 478 |
if (settingsButton2) {
|
| 479 |
+
settingsButton2.addEventListener("click", window.loadCharacterSection);
|
|
|
|
|
|
|
|
|
|
| 480 |
}
|
| 481 |
}
|
| 482 |
await attachCharacterSection();
|
|
|
|
| 918 |
}
|
| 919 |
if (window.kimiDB && window.kimiDB.db) {
|
| 920 |
try {
|
| 921 |
+
await window.kimiDB.db.conversations.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 922 |
} catch (error) {
|
| 923 |
console.error("Error deleting conversations:", error);
|
| 924 |
}
|
|
|
|
| 968 |
if (personalityPayload) {
|
| 969 |
const { character, traits } = personalityPayload;
|
| 970 |
const defaults = (window.getTraitDefaults && window.getTraitDefaults()) || {
|
| 971 |
+
affection: 55, // Baseline affection default
|
| 972 |
romance: 50,
|
| 973 |
empathy: 75,
|
| 974 |
playfulness: 55,
|
|
|
|
| 1244 |
} catch {
|
| 1245 |
} finally {
|
| 1246 |
lastTraits = {};
|
| 1247 |
+
if (window.updateGlobalPersonalityUI) {
|
| 1248 |
+
try {
|
| 1249 |
+
await window.updateGlobalPersonalityUI();
|
| 1250 |
+
} catch {}
|
| 1251 |
+
}
|
| 1252 |
}
|
| 1253 |
}, 120); // small debounce
|
| 1254 |
});
|
kimi-js/kimi-utils.js
CHANGED
|
@@ -1017,17 +1017,17 @@ class KimiVideoManager {
|
|
| 1017 |
let weights = candidateVideos.map(video => {
|
| 1018 |
if (category === "speakingPositive") {
|
| 1019 |
// Positive videos favored by affection, romance, and humor
|
| 1020 |
-
const base = 1 + (affection / 100) * 0.4; //
|
| 1021 |
let bonus = 0;
|
| 1022 |
const rom = typeof traits.romance === "number" ? traits.romance : 50;
|
| 1023 |
const hum = typeof traits.humor === "number" ? traits.humor : 50;
|
| 1024 |
-
if (emotion === "romantic") bonus += (rom / 100) * 0.3; //
|
| 1025 |
-
if (emotion === "laughing") bonus += (hum / 100) * 0.3; //
|
| 1026 |
return base + bonus;
|
| 1027 |
}
|
| 1028 |
if (category === "speakingNegative") {
|
| 1029 |
// Negative videos when affection is low (reduced weight to balance)
|
| 1030 |
-
return 1 + ((100 - affection) / 100) * 0.3; //
|
| 1031 |
}
|
| 1032 |
if (category === "neutral") {
|
| 1033 |
// Neutral videos when affection is moderate, also influenced by intelligence
|
|
@@ -2295,13 +2295,23 @@ class KimiUIStateManager {
|
|
| 2295 |
this.state.activeTab = tabName;
|
| 2296 |
if (this.tabManager) this.tabManager.activateTab(tabName);
|
| 2297 |
}
|
| 2298 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2299 |
const v = Number(value) || 0;
|
| 2300 |
const clamped = Math.max(0, Math.min(100, v));
|
| 2301 |
this.state.favorability = clamped;
|
| 2302 |
window.KimiDOMUtils.setText("#favorability-text", `${clamped.toFixed(2)}%`);
|
| 2303 |
window.KimiDOMUtils.get("#favorability-bar").style.width = `${clamped}%`;
|
| 2304 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2305 |
async setTranscript(text) {
|
| 2306 |
this.state.transcript = text;
|
| 2307 |
// Always use the proper transcript management via VoiceManager
|
|
|
|
| 1017 |
let weights = candidateVideos.map(video => {
|
| 1018 |
if (category === "speakingPositive") {
|
| 1019 |
// Positive videos favored by affection, romance, and humor
|
| 1020 |
+
const base = 1 + (affection / 100) * 0.4; // Affection influence factor
|
| 1021 |
let bonus = 0;
|
| 1022 |
const rom = typeof traits.romance === "number" ? traits.romance : 50;
|
| 1023 |
const hum = typeof traits.humor === "number" ? traits.humor : 50;
|
| 1024 |
+
if (emotion === "romantic") bonus += (rom / 100) * 0.3; // Romance context bonus
|
| 1025 |
+
if (emotion === "laughing") bonus += (hum / 100) * 0.3; // Humor context bonus
|
| 1026 |
return base + bonus;
|
| 1027 |
}
|
| 1028 |
if (category === "speakingNegative") {
|
| 1029 |
// Negative videos when affection is low (reduced weight to balance)
|
| 1030 |
+
return 1 + ((100 - affection) / 100) * 0.3; // Low-affection influence factor
|
| 1031 |
}
|
| 1032 |
if (category === "neutral") {
|
| 1033 |
// Neutral videos when affection is moderate, also influenced by intelligence
|
|
|
|
| 2295 |
this.state.activeTab = tabName;
|
| 2296 |
if (this.tabManager) this.tabManager.activateTab(tabName);
|
| 2297 |
}
|
| 2298 |
+
/**
|
| 2299 |
+
* @deprecated Prefer calling updateGlobalPersonalityUI() after updating traits.
|
| 2300 |
+
* This direct setter will be removed in a future cleanup.
|
| 2301 |
+
*/
|
| 2302 |
+
setPersonalityAverage(value) {
|
| 2303 |
const v = Number(value) || 0;
|
| 2304 |
const clamped = Math.max(0, Math.min(100, v));
|
| 2305 |
this.state.favorability = clamped;
|
| 2306 |
window.KimiDOMUtils.setText("#favorability-text", `${clamped.toFixed(2)}%`);
|
| 2307 |
window.KimiDOMUtils.get("#favorability-bar").style.width = `${clamped}%`;
|
| 2308 |
}
|
| 2309 |
+
/**
|
| 2310 |
+
* @deprecated Use setPersonalityAverage() (itself deprecated) or updateGlobalPersonalityUI().
|
| 2311 |
+
*/
|
| 2312 |
+
setFavorability(value) {
|
| 2313 |
+
this.setPersonalityAverage(value);
|
| 2314 |
+
}
|
| 2315 |
async setTranscript(text) {
|
| 2316 |
this.state.transcript = text;
|
| 2317 |
// Always use the proper transcript management via VoiceManager
|
kimi-js/kimi-voices.js
CHANGED
|
@@ -208,16 +208,16 @@ class KimiVoiceManager {
|
|
| 208 |
return;
|
| 209 |
}
|
| 210 |
|
| 211 |
-
//
|
| 212 |
if (!this.selectedLanguage) {
|
| 213 |
const selectedLanguage = await this.db?.getPreference("selectedLanguage", "en");
|
| 214 |
-
// Normalize legacy formats (en-US, en_US, us:en -> en) using shared util
|
| 215 |
this.selectedLanguage = window.KimiLanguageUtils.normalizeLanguageCode(selectedLanguage || "en") || "en";
|
| 216 |
}
|
|
|
|
| 217 |
|
| 218 |
const savedVoice = await this.db?.getPreference("selectedVoice", "auto");
|
| 219 |
|
| 220 |
-
const filteredVoices = this.getVoicesForLanguage(
|
| 221 |
|
| 222 |
if (savedVoice && savedVoice !== "auto") {
|
| 223 |
// Only search within language-compatible voices
|
|
@@ -225,7 +225,7 @@ class KimiVoiceManager {
|
|
| 225 |
if (foundVoice) {
|
| 226 |
this.currentVoice = foundVoice;
|
| 227 |
console.log(
|
| 228 |
-
`🎤 Voice restored from cache: "${foundVoice.name}" (${foundVoice.lang}) for language "${
|
| 229 |
);
|
| 230 |
this.updateVoiceSelector();
|
| 231 |
this._initializingVoices = false;
|
|
@@ -233,7 +233,7 @@ class KimiVoiceManager {
|
|
| 233 |
} else {
|
| 234 |
// Saved voice not compatible with current language, fall back to auto-selection
|
| 235 |
console.log(
|
| 236 |
-
`🎤 Saved voice "${savedVoice}" not compatible with language "${
|
| 237 |
);
|
| 238 |
await this.db?.setPreference("selectedVoice", "auto");
|
| 239 |
}
|
|
@@ -333,7 +333,7 @@ class KimiVoiceManager {
|
|
| 333 |
// Debug: Show what voices are available and why they don't match
|
| 334 |
if (filteredVoices.length > 0 && filteredVoices.length <= 5) {
|
| 335 |
console.log(
|
| 336 |
-
`🎤 Available voices for ${
|
| 337 |
filteredVoices.map(v => ({
|
| 338 |
name: v.name,
|
| 339 |
lang: v.lang,
|
|
@@ -362,7 +362,7 @@ class KimiVoiceManager {
|
|
| 362 |
} else {
|
| 363 |
// Log successful voice selection with language info
|
| 364 |
console.log(
|
| 365 |
-
`🎤 Voice loaded: "${this.currentVoice.name}" (${this.currentVoice.lang}) for language "${
|
| 366 |
);
|
| 367 |
}
|
| 368 |
|
|
@@ -861,16 +861,26 @@ class KimiVoiceManager {
|
|
| 861 |
}
|
| 862 |
|
| 863 |
// ===== SPEECH RECOGNITION =====
|
| 864 |
-
setupSpeechRecognition() {
|
| 865 |
if (!this.SpeechRecognition) {
|
| 866 |
// Do not show a UI message during initial load; only log.
|
| 867 |
console.log("Your browser does not support speech recognition.");
|
| 868 |
return;
|
| 869 |
}
|
|
|
|
| 870 |
this.recognition = new this.SpeechRecognition();
|
| 871 |
this.recognition.continuous = true;
|
| 872 |
-
|
| 873 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 874 |
this.recognition.interimResults = true;
|
| 875 |
|
| 876 |
// Add onstart handler to confirm permission
|
|
@@ -1048,9 +1058,9 @@ class KimiVoiceManager {
|
|
| 1048 |
return;
|
| 1049 |
}
|
| 1050 |
|
| 1051 |
-
// If permission
|
| 1052 |
if (this.micPermissionGranted) {
|
| 1053 |
-
console.log("🎤
|
| 1054 |
this.startRecognitionDirectly();
|
| 1055 |
return;
|
| 1056 |
}
|
|
@@ -1223,19 +1233,30 @@ class KimiVoiceManager {
|
|
| 1223 |
} // Helper to modulate emotion based on personality traits
|
| 1224 |
_modulateEmotionByPersonality(emotion) {
|
| 1225 |
try {
|
|
|
|
| 1226 |
let avg = 50;
|
| 1227 |
-
if (
|
| 1228 |
-
|
| 1229 |
-
|
| 1230 |
-
|
| 1231 |
-
|
| 1232 |
-
|
| 1233 |
-
|
| 1234 |
-
|
| 1235 |
-
|
| 1236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1237 |
}
|
| 1238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1239 |
return emotion;
|
| 1240 |
} catch (e) {
|
| 1241 |
return emotion;
|
|
@@ -1362,10 +1383,56 @@ class KimiVoiceManager {
|
|
| 1362 |
console.warn(`🎤 No voice found for language "${newLang}"`);
|
| 1363 |
}
|
| 1364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1365 |
if (this.recognition) {
|
| 1366 |
-
|
| 1367 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1368 |
}
|
|
|
|
|
|
|
|
|
|
| 1369 |
}
|
| 1370 |
|
| 1371 |
async updateSelectedCharacter() {
|
|
|
|
| 208 |
return;
|
| 209 |
}
|
| 210 |
|
| 211 |
+
// Resolve effective selectedLanguage if missing
|
| 212 |
if (!this.selectedLanguage) {
|
| 213 |
const selectedLanguage = await this.db?.getPreference("selectedLanguage", "en");
|
|
|
|
| 214 |
this.selectedLanguage = window.KimiLanguageUtils.normalizeLanguageCode(selectedLanguage || "en") || "en";
|
| 215 |
}
|
| 216 |
+
const effectiveLang = await this.getEffectiveLanguage(this.selectedLanguage);
|
| 217 |
|
| 218 |
const savedVoice = await this.db?.getPreference("selectedVoice", "auto");
|
| 219 |
|
| 220 |
+
const filteredVoices = this.getVoicesForLanguage(effectiveLang);
|
| 221 |
|
| 222 |
if (savedVoice && savedVoice !== "auto") {
|
| 223 |
// Only search within language-compatible voices
|
|
|
|
| 225 |
if (foundVoice) {
|
| 226 |
this.currentVoice = foundVoice;
|
| 227 |
console.log(
|
| 228 |
+
`🎤 Voice restored from cache: "${foundVoice.name}" (${foundVoice.lang}) for language "${effectiveLang}"`
|
| 229 |
);
|
| 230 |
this.updateVoiceSelector();
|
| 231 |
this._initializingVoices = false;
|
|
|
|
| 233 |
} else {
|
| 234 |
// Saved voice not compatible with current language, fall back to auto-selection
|
| 235 |
console.log(
|
| 236 |
+
`🎤 Saved voice "${savedVoice}" not compatible with language "${effectiveLang}", using auto-selection`
|
| 237 |
);
|
| 238 |
await this.db?.setPreference("selectedVoice", "auto");
|
| 239 |
}
|
|
|
|
| 333 |
// Debug: Show what voices are available and why they don't match
|
| 334 |
if (filteredVoices.length > 0 && filteredVoices.length <= 5) {
|
| 335 |
console.log(
|
| 336 |
+
`🎤 Available voices for ${effectiveLang}:`,
|
| 337 |
filteredVoices.map(v => ({
|
| 338 |
name: v.name,
|
| 339 |
lang: v.lang,
|
|
|
|
| 362 |
} else {
|
| 363 |
// Log successful voice selection with language info
|
| 364 |
console.log(
|
| 365 |
+
`🎤 Voice loaded: "${this.currentVoice.name}" (${this.currentVoice.lang}) for language "${effectiveLang}"`
|
| 366 |
);
|
| 367 |
}
|
| 368 |
|
|
|
|
| 861 |
}
|
| 862 |
|
| 863 |
// ===== SPEECH RECOGNITION =====
|
| 864 |
+
async setupSpeechRecognition() {
|
| 865 |
if (!this.SpeechRecognition) {
|
| 866 |
// Do not show a UI message during initial load; only log.
|
| 867 |
console.log("Your browser does not support speech recognition.");
|
| 868 |
return;
|
| 869 |
}
|
| 870 |
+
// Always create a fresh instance (some browsers cache language at construction time)
|
| 871 |
this.recognition = new this.SpeechRecognition();
|
| 872 |
this.recognition.continuous = true;
|
| 873 |
+
|
| 874 |
+
// Resolve effective language (block invalid 'auto')
|
| 875 |
+
const normalized = await this.getEffectiveLanguage(this.selectedLanguage);
|
| 876 |
+
const langCode = this.getLanguageCode(normalized || "en");
|
| 877 |
+
try {
|
| 878 |
+
this.recognition.lang = langCode;
|
| 879 |
+
} catch (e) {
|
| 880 |
+
console.warn("Could not set recognition.lang, fallback en-US", e);
|
| 881 |
+
this.recognition.lang = "en-US";
|
| 882 |
+
}
|
| 883 |
+
console.log(`🎤 SpeechRecognition initialized (lang=${this.recognition.lang})`);
|
| 884 |
this.recognition.interimResults = true;
|
| 885 |
|
| 886 |
// Add onstart handler to confirm permission
|
|
|
|
| 1058 |
return;
|
| 1059 |
}
|
| 1060 |
|
| 1061 |
+
// If microphone permission already granted, start directly
|
| 1062 |
if (this.micPermissionGranted) {
|
| 1063 |
+
console.log("🎤 Microphone permission already granted");
|
| 1064 |
this.startRecognitionDirectly();
|
| 1065 |
return;
|
| 1066 |
}
|
|
|
|
| 1233 |
} // Helper to modulate emotion based on personality traits
|
| 1234 |
_modulateEmotionByPersonality(emotion) {
|
| 1235 |
try {
|
| 1236 |
+
// Obtain full traits if possible for a more robust modulation
|
| 1237 |
let avg = 50;
|
| 1238 |
+
if (window.kimiEmotionSystem && window.kimiEmotionSystem.db) {
|
| 1239 |
+
// Attempt synchronous-like cache via memory first
|
| 1240 |
+
const traits = {
|
| 1241 |
+
affection: this.memory?.affectionTrait,
|
| 1242 |
+
playfulness: this.memory?.playfulnessTrait,
|
| 1243 |
+
intelligence: this.memory?.intelligenceTrait,
|
| 1244 |
+
empathy: this.memory?.empathyTrait,
|
| 1245 |
+
humor: this.memory?.humorTrait,
|
| 1246 |
+
romance: this.memory?.romanceTrait
|
| 1247 |
+
};
|
| 1248 |
+
// If at least affection present, compute average using emotion system helper
|
| 1249 |
+
if (typeof traits.affection === "number") {
|
| 1250 |
+
avg = window.kimiEmotionSystem.calculatePersonalityAverage(traits);
|
| 1251 |
+
}
|
| 1252 |
+
} else if (this.memory && typeof this.memory.affectionTrait === "number") {
|
| 1253 |
+
avg = this.memory.affectionTrait; // fallback
|
| 1254 |
}
|
| 1255 |
|
| 1256 |
+
// Weighted interpretation: very low affection still softens positive expression
|
| 1257 |
+
// If overall avg low, dampen by shifting to 'shy'.
|
| 1258 |
+
if (avg <= 20 && emotion !== "neutral") return "shy";
|
| 1259 |
+
if (avg <= 40 && emotion === "positive") return "shy";
|
| 1260 |
return emotion;
|
| 1261 |
} catch (e) {
|
| 1262 |
return emotion;
|
|
|
|
| 1383 |
console.warn(`🎤 No voice found for language "${newLang}"`);
|
| 1384 |
}
|
| 1385 |
|
| 1386 |
+
// Update recognition language safely (recreate instance to avoid stale internal state)
|
| 1387 |
+
this._refreshRecognitionLanguage(newLang);
|
| 1388 |
+
}
|
| 1389 |
+
|
| 1390 |
+
/**
|
| 1391 |
+
* Recreate speech recognition instance with a new language.
|
| 1392 |
+
* Some browsers (notably Chrome) may ignore lang changes mid-session; recreating ensures consistency.
|
| 1393 |
+
*/
|
| 1394 |
+
async _refreshRecognitionLanguage(newLang) {
|
| 1395 |
+
if (!this.SpeechRecognition) return;
|
| 1396 |
+
const wasListening = this.isListening;
|
| 1397 |
if (this.recognition) {
|
| 1398 |
+
try {
|
| 1399 |
+
if (this.isListening) this.recognition.stop();
|
| 1400 |
+
} catch {}
|
| 1401 |
+
this.recognition.onresult = null;
|
| 1402 |
+
this.recognition.onstart = null;
|
| 1403 |
+
this.recognition.onend = null;
|
| 1404 |
+
this.recognition.onerror = null;
|
| 1405 |
+
this.recognition = null;
|
| 1406 |
+
}
|
| 1407 |
+
this.selectedLanguage = newLang;
|
| 1408 |
+
await this.setupSpeechRecognition();
|
| 1409 |
+
console.log(`🎤 Recognition language refreshed -> ${this.recognition?.lang}`);
|
| 1410 |
+
// Restart listening if it was active
|
| 1411 |
+
if (wasListening) {
|
| 1412 |
+
// Small delay to allow new instance to settle
|
| 1413 |
+
setTimeout(() => {
|
| 1414 |
+
this.startListening();
|
| 1415 |
+
}, 150);
|
| 1416 |
+
}
|
| 1417 |
+
}
|
| 1418 |
+
|
| 1419 |
+
// Return a normalized concrete language code (primary subtag) never 'auto'
|
| 1420 |
+
async getEffectiveLanguage(raw) {
|
| 1421 |
+
let base = raw || this.selectedLanguage || "en";
|
| 1422 |
+
if (base === "auto") {
|
| 1423 |
+
try {
|
| 1424 |
+
if (window.KimiLanguageUtils?.getLanguage) {
|
| 1425 |
+
base = await window.KimiLanguageUtils.getLanguage();
|
| 1426 |
+
} else {
|
| 1427 |
+
base = navigator.language?.split("-")[0] || "en";
|
| 1428 |
+
}
|
| 1429 |
+
} catch {
|
| 1430 |
+
base = "en";
|
| 1431 |
+
}
|
| 1432 |
}
|
| 1433 |
+
return window.KimiLanguageUtils?.normalizeLanguageCode
|
| 1434 |
+
? window.KimiLanguageUtils.normalizeLanguageCode(base)
|
| 1435 |
+
: base || "en";
|
| 1436 |
}
|
| 1437 |
|
| 1438 |
async updateSelectedCharacter() {
|
kimi-locale/de.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "Zuhören Beginnen",
|
| 96 |
"kimi_affection_level": "💖 Kimis Zuneigungsgrad",
|
| 97 |
"affection_level_of": "💖 Zuneigungsgrad von {name}",
|
|
|
|
| 98 |
"greeting_low": "Hallo.",
|
| 99 |
"greeting_mid": "Hallo. Wie kann ich dir helfen?",
|
| 100 |
"greeting_high": "Hallo mein Liebling! 💕",
|
|
|
|
| 95 |
"start_listening": "Zuhören Beginnen",
|
| 96 |
"kimi_affection_level": "💖 Kimis Zuneigungsgrad",
|
| 97 |
"affection_level_of": "💖 Zuneigungsgrad von {name}",
|
| 98 |
+
"personality_average_of": "💖 Persönlichkeitsdurchschnitt von {name}",
|
| 99 |
"greeting_low": "Hallo.",
|
| 100 |
"greeting_mid": "Hallo. Wie kann ich dir helfen?",
|
| 101 |
"greeting_high": "Hallo mein Liebling! 💕",
|
kimi-locale/en.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "Start Listening",
|
| 96 |
"kimi_affection_level": "💖 Kimi's Affection Level",
|
| 97 |
"affection_level_of": "💖 Affection level of {name}",
|
|
|
|
| 98 |
"greeting_low": "Hello.",
|
| 99 |
"greeting_mid": "Hi. How can I help you?",
|
| 100 |
"greeting_high": "Hello my love! 💕",
|
|
|
|
| 95 |
"start_listening": "Start Listening",
|
| 96 |
"kimi_affection_level": "💖 Kimi's Affection Level",
|
| 97 |
"affection_level_of": "💖 Affection level of {name}",
|
| 98 |
+
"personality_average_of": "💖 Personality average of {name}",
|
| 99 |
"greeting_low": "Hello.",
|
| 100 |
"greeting_mid": "Hi. How can I help you?",
|
| 101 |
"greeting_high": "Hello my love! 💕",
|
kimi-locale/es.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "Comenzar a Escuchar",
|
| 96 |
"kimi_affection_level": "💖 Nivel de Afecto de Kimi",
|
| 97 |
"affection_level_of": "💖 Nivel de afecto de {name}",
|
|
|
|
| 98 |
"greeting_low": "Hola.",
|
| 99 |
"greeting_mid": "Hola. ¿Cómo puedo ayudarte?",
|
| 100 |
"greeting_high": "¡Hola mi amor! 💕",
|
|
|
|
| 95 |
"start_listening": "Comenzar a Escuchar",
|
| 96 |
"kimi_affection_level": "💖 Nivel de Afecto de Kimi",
|
| 97 |
"affection_level_of": "💖 Nivel de afecto de {name}",
|
| 98 |
+
"personality_average_of": "💖 Promedio de personalidad de {name}",
|
| 99 |
"greeting_low": "Hola.",
|
| 100 |
"greeting_mid": "Hola. ¿Cómo puedo ayudarte?",
|
| 101 |
"greeting_high": "¡Hola mi amor! 💕",
|
kimi-locale/fr.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "Commencer à écouter",
|
| 96 |
"kimi_affection_level": "💖 Niveau d'affection de Kimi",
|
| 97 |
"affection_level_of": "💖 Niveau d'affection de {name}",
|
|
|
|
| 98 |
"greeting_low": "Bonjour.",
|
| 99 |
"greeting_mid": "Bonjour. Comment puis-je vous aider ?",
|
| 100 |
"greeting_high": "Salut mon amour ! 💕",
|
|
|
|
| 95 |
"start_listening": "Commencer à écouter",
|
| 96 |
"kimi_affection_level": "💖 Niveau d'affection de Kimi",
|
| 97 |
"affection_level_of": "💖 Niveau d'affection de {name}",
|
| 98 |
+
"personality_average_of": "💖 Moyenne personnalité de {name}",
|
| 99 |
"greeting_low": "Bonjour.",
|
| 100 |
"greeting_mid": "Bonjour. Comment puis-je vous aider ?",
|
| 101 |
"greeting_high": "Salut mon amour ! 💕",
|
kimi-locale/it.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "Inizia ad Ascoltare",
|
| 96 |
"kimi_affection_level": "💖 Livello di Affetto di Kimi",
|
| 97 |
"affection_level_of": "💖 Livello di affetto di {name}",
|
|
|
|
| 98 |
"greeting_low": "Ciao.",
|
| 99 |
"greeting_mid": "Ciao. Come posso aiutarti?",
|
| 100 |
"greeting_high": "Ciao amore mio! 💕",
|
|
|
|
| 95 |
"start_listening": "Inizia ad Ascoltare",
|
| 96 |
"kimi_affection_level": "💖 Livello di Affetto di Kimi",
|
| 97 |
"affection_level_of": "💖 Livello di affetto di {name}",
|
| 98 |
+
"personality_average_of": "💖 Media personalità di {name}",
|
| 99 |
"greeting_low": "Ciao.",
|
| 100 |
"greeting_mid": "Ciao. Come posso aiutarti?",
|
| 101 |
"greeting_high": "Ciao amore mio! 💕",
|
kimi-locale/ja.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "聞き始める",
|
| 96 |
"kimi_affection_level": "💖 Kimiの愛情レベル",
|
| 97 |
"affection_level_of": "💖 {name}の愛情レベル",
|
|
|
|
| 98 |
"greeting_low": "こんにちは。",
|
| 99 |
"greeting_mid": "こんにちは。どのようにお手伝いできますか?",
|
| 100 |
"greeting_high": "こんにちは、愛しい人! 💕",
|
|
|
|
| 95 |
"start_listening": "聞き始める",
|
| 96 |
"kimi_affection_level": "💖 Kimiの愛情レベル",
|
| 97 |
"affection_level_of": "💖 {name}の愛情レベル",
|
| 98 |
+
"personality_average_of": "💖 {name}のパーソナリティ平均",
|
| 99 |
"greeting_low": "こんにちは。",
|
| 100 |
"greeting_mid": "こんにちは。どのようにお手伝いできますか?",
|
| 101 |
"greeting_high": "こんにちは、愛しい人! 💕",
|
kimi-locale/zh.json
CHANGED
|
@@ -95,6 +95,7 @@
|
|
| 95 |
"start_listening": "开始聆听",
|
| 96 |
"kimi_affection_level": "💖 Kimi的喜爱程度",
|
| 97 |
"affection_level_of": "💖 {name}的喜爱程度",
|
|
|
|
| 98 |
"greeting_low": "你好。",
|
| 99 |
"greeting_mid": "你好。我可以帮助您什么?",
|
| 100 |
"greeting_high": "你好,我的爱! 💕",
|
|
|
|
| 95 |
"start_listening": "开始聆听",
|
| 96 |
"kimi_affection_level": "💖 Kimi的喜爱程度",
|
| 97 |
"affection_level_of": "💖 {name}的喜爱程度",
|
| 98 |
+
"personality_average_of": "💖 {name}的人格平均值",
|
| 99 |
"greeting_low": "你好。",
|
| 100 |
"greeting_mid": "你好。我可以帮助您什么?",
|
| 101 |
"greeting_high": "你好,我的爱! 💕",
|