koishi-plugin-chatluna-affinity 0.3.0-beta.2 → 0.3.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +198 -185
- package/package.json +6 -8
package/lib/index.js
CHANGED
|
@@ -1284,6 +1284,190 @@ async function fetchGroupMemberIds(session, log) {
|
|
|
1284
1284
|
}
|
|
1285
1285
|
}
|
|
1286
1286
|
|
|
1287
|
+
// src/services/affinity/calculator.ts
|
|
1288
|
+
function normalizeAction(action) {
|
|
1289
|
+
const text = typeof action === "string" ? action.toLowerCase() : "";
|
|
1290
|
+
if (text === "increase" || text === "decrease") return text;
|
|
1291
|
+
return "increase";
|
|
1292
|
+
}
|
|
1293
|
+
function resolveShortTermConfig(config) {
|
|
1294
|
+
const cfg = config?.affinityDynamics?.shortTerm || {};
|
|
1295
|
+
const defaults = AFFINITY_DYNAMICS_DEFAULTS.shortTerm;
|
|
1296
|
+
const promoteRaw = Number(cfg.promoteThreshold);
|
|
1297
|
+
const demoteRaw = Number(cfg.demoteThreshold);
|
|
1298
|
+
let promoteThreshold = Number.isFinite(promoteRaw) ? Math.round(promoteRaw) : defaults.promoteThreshold;
|
|
1299
|
+
let demoteThreshold = Number.isFinite(demoteRaw) ? Math.round(demoteRaw) : defaults.demoteThreshold;
|
|
1300
|
+
if (promoteThreshold <= demoteThreshold) {
|
|
1301
|
+
const midpoint = Math.round((promoteThreshold + demoteThreshold) / 2) || 0;
|
|
1302
|
+
promoteThreshold = midpoint + 15;
|
|
1303
|
+
demoteThreshold = midpoint - 15;
|
|
1304
|
+
}
|
|
1305
|
+
const promoteStepRaw = Number(cfg.longTermPromoteStep);
|
|
1306
|
+
const demoteStepRaw = Number(cfg.longTermDemoteStep);
|
|
1307
|
+
const longTermPromoteStep = Math.max(
|
|
1308
|
+
1,
|
|
1309
|
+
Math.round(
|
|
1310
|
+
Math.abs(
|
|
1311
|
+
Number.isFinite(promoteStepRaw) ? promoteStepRaw : Number.isFinite(cfg.longTermStep) ? cfg.longTermStep : defaults.longTermPromoteStep
|
|
1312
|
+
)
|
|
1313
|
+
)
|
|
1314
|
+
);
|
|
1315
|
+
const longTermDemoteStep = Math.max(
|
|
1316
|
+
1,
|
|
1317
|
+
Math.round(
|
|
1318
|
+
Math.abs(
|
|
1319
|
+
Number.isFinite(demoteStepRaw) ? demoteStepRaw : Number.isFinite(cfg.longTermStep) ? cfg.longTermStep : defaults.longTermDemoteStep
|
|
1320
|
+
)
|
|
1321
|
+
)
|
|
1322
|
+
);
|
|
1323
|
+
return {
|
|
1324
|
+
promoteThreshold,
|
|
1325
|
+
demoteThreshold,
|
|
1326
|
+
longTermPromoteStep,
|
|
1327
|
+
longTermDemoteStep
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
function resolveActionWindowConfig(config) {
|
|
1331
|
+
const cfg = config?.affinityDynamics?.actionWindow || {};
|
|
1332
|
+
const defaults = AFFINITY_DYNAMICS_DEFAULTS.actionWindow;
|
|
1333
|
+
const windowHoursRaw = Number(cfg.windowHours);
|
|
1334
|
+
const windowHours = Math.max(
|
|
1335
|
+
1,
|
|
1336
|
+
Number.isFinite(windowHoursRaw) ? windowHoursRaw : defaults.windowHours
|
|
1337
|
+
);
|
|
1338
|
+
const increaseBonus = Number.isFinite(cfg.increaseBonus) ? cfg.increaseBonus : defaults.increaseBonus;
|
|
1339
|
+
const decreaseBonus = Number.isFinite(cfg.decreaseBonus) ? cfg.decreaseBonus : defaults.decreaseBonus;
|
|
1340
|
+
const bonusChatThresholdRaw = Number(cfg.bonusChatThreshold);
|
|
1341
|
+
const bonusChatThreshold = Math.max(
|
|
1342
|
+
0,
|
|
1343
|
+
Number.isFinite(bonusChatThresholdRaw) ? Math.round(bonusChatThresholdRaw) : defaults.bonusChatThreshold
|
|
1344
|
+
);
|
|
1345
|
+
const maxEntriesRaw = Number(cfg.maxEntries);
|
|
1346
|
+
const maxEntries = Math.max(
|
|
1347
|
+
10,
|
|
1348
|
+
Number.isFinite(maxEntriesRaw) ? Math.round(maxEntriesRaw) : defaults.maxEntries
|
|
1349
|
+
);
|
|
1350
|
+
return {
|
|
1351
|
+
windowHours,
|
|
1352
|
+
windowMs: windowHours * 3600 * 1e3,
|
|
1353
|
+
increaseBonus,
|
|
1354
|
+
decreaseBonus,
|
|
1355
|
+
bonusChatThreshold,
|
|
1356
|
+
maxEntries
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function resolveCoefficientConfig(config) {
|
|
1360
|
+
const cfg = config?.affinityDynamics?.coefficient || {};
|
|
1361
|
+
const defaults = AFFINITY_DYNAMICS_DEFAULTS.coefficient;
|
|
1362
|
+
const base = Number.isFinite(cfg.base) ? cfg.base : defaults.base;
|
|
1363
|
+
const maxDrop = Math.max(
|
|
1364
|
+
0,
|
|
1365
|
+
Number.isFinite(cfg.maxDrop) ? cfg.maxDrop : defaults.maxDrop
|
|
1366
|
+
);
|
|
1367
|
+
const maxBoost = Math.max(
|
|
1368
|
+
0,
|
|
1369
|
+
Number.isFinite(cfg.maxBoost) ? cfg.maxBoost : defaults.maxBoost
|
|
1370
|
+
);
|
|
1371
|
+
const decayPerDay = Math.max(
|
|
1372
|
+
0,
|
|
1373
|
+
Number.isFinite(cfg.decayPerDay) ? cfg.decayPerDay : defaults.decayPerDay
|
|
1374
|
+
);
|
|
1375
|
+
const boostPerDay = Math.max(
|
|
1376
|
+
0,
|
|
1377
|
+
Number.isFinite(cfg.boostPerDay) ? cfg.boostPerDay : defaults.boostPerDay
|
|
1378
|
+
);
|
|
1379
|
+
const min = base - maxDrop;
|
|
1380
|
+
const max = base + maxBoost;
|
|
1381
|
+
return { base, maxDrop, maxBoost, decayPerDay, boostPerDay, min, max };
|
|
1382
|
+
}
|
|
1383
|
+
function summarizeActionEntries(rawEntries, windowMs, nowMs) {
|
|
1384
|
+
const fallback = {
|
|
1385
|
+
entries: [],
|
|
1386
|
+
counts: { increase: 0, decrease: 0 },
|
|
1387
|
+
total: 0
|
|
1388
|
+
};
|
|
1389
|
+
if (!Array.isArray(rawEntries)) return fallback;
|
|
1390
|
+
const cutoff = nowMs - windowMs;
|
|
1391
|
+
const entries = [];
|
|
1392
|
+
const counts = { increase: 0, decrease: 0 };
|
|
1393
|
+
for (const entry of rawEntries) {
|
|
1394
|
+
if (!entry) continue;
|
|
1395
|
+
const ts = Number(entry.timestamp);
|
|
1396
|
+
if (!Number.isFinite(ts) || ts < cutoff) continue;
|
|
1397
|
+
const normalizedAction = normalizeAction(entry.action);
|
|
1398
|
+
entries.push({ action: normalizedAction, timestamp: ts });
|
|
1399
|
+
counts[normalizedAction] += 1;
|
|
1400
|
+
}
|
|
1401
|
+
return { entries, counts, total: counts.increase + counts.decrease };
|
|
1402
|
+
}
|
|
1403
|
+
function appendActionEntry(entries, action, nowMs, maxEntries) {
|
|
1404
|
+
const next = Array.isArray(entries) ? [...entries] : [];
|
|
1405
|
+
next.push({ action: normalizeAction(action), timestamp: nowMs });
|
|
1406
|
+
if (next.length > maxEntries) next.splice(0, next.length - maxEntries);
|
|
1407
|
+
return next;
|
|
1408
|
+
}
|
|
1409
|
+
function computeShortTermReset() {
|
|
1410
|
+
return 0;
|
|
1411
|
+
}
|
|
1412
|
+
function dayNumber2(date) {
|
|
1413
|
+
return Math.floor(date.getTime() / 864e5);
|
|
1414
|
+
}
|
|
1415
|
+
function computeDailyStreak(previousStreak, lastInteractionAt, now) {
|
|
1416
|
+
const last = lastInteractionAt instanceof Date ? lastInteractionAt : null;
|
|
1417
|
+
const currentDay = dayNumber2(now);
|
|
1418
|
+
const previousDay = last ? dayNumber2(last) : null;
|
|
1419
|
+
if (previousDay === null) return 1;
|
|
1420
|
+
if (previousDay === currentDay) return Math.max(1, previousStreak || 1);
|
|
1421
|
+
if (previousDay === currentDay - 1)
|
|
1422
|
+
return Math.max(1, (previousStreak || 0) + 1);
|
|
1423
|
+
return 1;
|
|
1424
|
+
}
|
|
1425
|
+
function computeCoefficientValue(coefConfig, streak, lastInteractionAt, now, todayIncreaseCount = 0, todayDecreaseCount = 0) {
|
|
1426
|
+
const lastMs = lastInteractionAt instanceof Date ? lastInteractionAt.getTime() : null;
|
|
1427
|
+
const nowMs = now.getTime();
|
|
1428
|
+
const inactivityDays = lastMs ? Math.max(0, Math.floor((nowMs - lastMs) / 864e5)) : 0;
|
|
1429
|
+
const hasInteractedToday = inactivityDays === 0;
|
|
1430
|
+
const isPositiveDay = todayIncreaseCount > todayDecreaseCount;
|
|
1431
|
+
const isNegativeDay = todayDecreaseCount > todayIncreaseCount;
|
|
1432
|
+
let decayPenalty = 0;
|
|
1433
|
+
let streakBoost = 0;
|
|
1434
|
+
if (!hasInteractedToday || isNegativeDay) {
|
|
1435
|
+
if (!hasInteractedToday) {
|
|
1436
|
+
decayPenalty = Math.min(
|
|
1437
|
+
coefConfig.maxDrop,
|
|
1438
|
+
inactivityDays * coefConfig.decayPerDay
|
|
1439
|
+
);
|
|
1440
|
+
} else if (isNegativeDay) {
|
|
1441
|
+
decayPenalty = Math.min(coefConfig.maxDrop, coefConfig.decayPerDay);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
if (hasInteractedToday && isPositiveDay && streak > 0) {
|
|
1445
|
+
streakBoost = Math.min(
|
|
1446
|
+
coefConfig.maxBoost,
|
|
1447
|
+
Math.max(0, (Math.max(1, streak) - 1) * coefConfig.boostPerDay)
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
const coefficient = clampFloat(
|
|
1451
|
+
coefConfig.base - decayPenalty + streakBoost,
|
|
1452
|
+
coefConfig.min,
|
|
1453
|
+
coefConfig.max
|
|
1454
|
+
);
|
|
1455
|
+
return { coefficient, decayPenalty, streakBoost, inactivityDays };
|
|
1456
|
+
}
|
|
1457
|
+
function composeState(longTerm, shortTerm, clampFn) {
|
|
1458
|
+
return {
|
|
1459
|
+
affinity: clampFn(longTerm),
|
|
1460
|
+
longTermAffinity: clampFn(longTerm),
|
|
1461
|
+
shortTermAffinity: Math.round(shortTerm)
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
function formatActionCounts(counts) {
|
|
1465
|
+
const safe = counts || {};
|
|
1466
|
+
const increase = Number(safe.increase) || 0;
|
|
1467
|
+
const decrease = Number(safe.decrease) || 0;
|
|
1468
|
+
return `\u63D0\u5347 ${increase} / \u964D\u4F4E ${decrease}`;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1287
1471
|
// src/services/affinity/store.ts
|
|
1288
1472
|
function createAffinityStore(options) {
|
|
1289
1473
|
const { ctx, config } = options;
|
|
@@ -1513,6 +1697,18 @@ function createAffinityStore(options) {
|
|
|
1513
1697
|
);
|
|
1514
1698
|
const existing = await load(scopeId, normalizedUserId);
|
|
1515
1699
|
if (!existing) return null;
|
|
1700
|
+
const parsedCoefficientState = extractState(existing).coefficientState;
|
|
1701
|
+
const now = /* @__PURE__ */ new Date();
|
|
1702
|
+
const nextStreak = computeDailyStreak(
|
|
1703
|
+
parsedCoefficientState?.streak,
|
|
1704
|
+
parsedCoefficientState?.lastInteractionAt || existing.lastInteractionAt,
|
|
1705
|
+
now
|
|
1706
|
+
);
|
|
1707
|
+
const nextCoefficientState = {
|
|
1708
|
+
...parsedCoefficientState,
|
|
1709
|
+
streak: nextStreak,
|
|
1710
|
+
lastInteractionAt: now
|
|
1711
|
+
};
|
|
1516
1712
|
return save(
|
|
1517
1713
|
{ ...seed, scopeId, userId: normalizedUserId },
|
|
1518
1714
|
Number.NaN,
|
|
@@ -1521,7 +1717,8 @@ function createAffinityStore(options) {
|
|
|
1521
1717
|
longTermAffinity: existing.longTermAffinity ?? existing.affinity,
|
|
1522
1718
|
shortTermAffinity: existing.shortTermAffinity ?? 0,
|
|
1523
1719
|
chatCount: Math.max(0, Number(existing.chatCount || 0)) + 1,
|
|
1524
|
-
|
|
1720
|
+
coefficientState: nextCoefficientState,
|
|
1721
|
+
lastInteractionAt: now
|
|
1525
1722
|
}
|
|
1526
1723
|
);
|
|
1527
1724
|
};
|
|
@@ -1562,190 +1759,6 @@ function createAffinityCache() {
|
|
|
1562
1759
|
};
|
|
1563
1760
|
}
|
|
1564
1761
|
|
|
1565
|
-
// src/services/affinity/calculator.ts
|
|
1566
|
-
function normalizeAction(action) {
|
|
1567
|
-
const text = typeof action === "string" ? action.toLowerCase() : "";
|
|
1568
|
-
if (text === "increase" || text === "decrease") return text;
|
|
1569
|
-
return "increase";
|
|
1570
|
-
}
|
|
1571
|
-
function resolveShortTermConfig(config) {
|
|
1572
|
-
const cfg = config?.affinityDynamics?.shortTerm || {};
|
|
1573
|
-
const defaults = AFFINITY_DYNAMICS_DEFAULTS.shortTerm;
|
|
1574
|
-
const promoteRaw = Number(cfg.promoteThreshold);
|
|
1575
|
-
const demoteRaw = Number(cfg.demoteThreshold);
|
|
1576
|
-
let promoteThreshold = Number.isFinite(promoteRaw) ? Math.round(promoteRaw) : defaults.promoteThreshold;
|
|
1577
|
-
let demoteThreshold = Number.isFinite(demoteRaw) ? Math.round(demoteRaw) : defaults.demoteThreshold;
|
|
1578
|
-
if (promoteThreshold <= demoteThreshold) {
|
|
1579
|
-
const midpoint = Math.round((promoteThreshold + demoteThreshold) / 2) || 0;
|
|
1580
|
-
promoteThreshold = midpoint + 15;
|
|
1581
|
-
demoteThreshold = midpoint - 15;
|
|
1582
|
-
}
|
|
1583
|
-
const promoteStepRaw = Number(cfg.longTermPromoteStep);
|
|
1584
|
-
const demoteStepRaw = Number(cfg.longTermDemoteStep);
|
|
1585
|
-
const longTermPromoteStep = Math.max(
|
|
1586
|
-
1,
|
|
1587
|
-
Math.round(
|
|
1588
|
-
Math.abs(
|
|
1589
|
-
Number.isFinite(promoteStepRaw) ? promoteStepRaw : Number.isFinite(cfg.longTermStep) ? cfg.longTermStep : defaults.longTermPromoteStep
|
|
1590
|
-
)
|
|
1591
|
-
)
|
|
1592
|
-
);
|
|
1593
|
-
const longTermDemoteStep = Math.max(
|
|
1594
|
-
1,
|
|
1595
|
-
Math.round(
|
|
1596
|
-
Math.abs(
|
|
1597
|
-
Number.isFinite(demoteStepRaw) ? demoteStepRaw : Number.isFinite(cfg.longTermStep) ? cfg.longTermStep : defaults.longTermDemoteStep
|
|
1598
|
-
)
|
|
1599
|
-
)
|
|
1600
|
-
);
|
|
1601
|
-
return {
|
|
1602
|
-
promoteThreshold,
|
|
1603
|
-
demoteThreshold,
|
|
1604
|
-
longTermPromoteStep,
|
|
1605
|
-
longTermDemoteStep
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
function resolveActionWindowConfig(config) {
|
|
1609
|
-
const cfg = config?.affinityDynamics?.actionWindow || {};
|
|
1610
|
-
const defaults = AFFINITY_DYNAMICS_DEFAULTS.actionWindow;
|
|
1611
|
-
const windowHoursRaw = Number(cfg.windowHours);
|
|
1612
|
-
const windowHours = Math.max(
|
|
1613
|
-
1,
|
|
1614
|
-
Number.isFinite(windowHoursRaw) ? windowHoursRaw : defaults.windowHours
|
|
1615
|
-
);
|
|
1616
|
-
const increaseBonus = Number.isFinite(cfg.increaseBonus) ? cfg.increaseBonus : defaults.increaseBonus;
|
|
1617
|
-
const decreaseBonus = Number.isFinite(cfg.decreaseBonus) ? cfg.decreaseBonus : defaults.decreaseBonus;
|
|
1618
|
-
const bonusChatThresholdRaw = Number(cfg.bonusChatThreshold);
|
|
1619
|
-
const bonusChatThreshold = Math.max(
|
|
1620
|
-
0,
|
|
1621
|
-
Number.isFinite(bonusChatThresholdRaw) ? Math.round(bonusChatThresholdRaw) : defaults.bonusChatThreshold
|
|
1622
|
-
);
|
|
1623
|
-
const maxEntriesRaw = Number(cfg.maxEntries);
|
|
1624
|
-
const maxEntries = Math.max(
|
|
1625
|
-
10,
|
|
1626
|
-
Number.isFinite(maxEntriesRaw) ? Math.round(maxEntriesRaw) : defaults.maxEntries
|
|
1627
|
-
);
|
|
1628
|
-
return {
|
|
1629
|
-
windowHours,
|
|
1630
|
-
windowMs: windowHours * 3600 * 1e3,
|
|
1631
|
-
increaseBonus,
|
|
1632
|
-
decreaseBonus,
|
|
1633
|
-
bonusChatThreshold,
|
|
1634
|
-
maxEntries
|
|
1635
|
-
};
|
|
1636
|
-
}
|
|
1637
|
-
function resolveCoefficientConfig(config) {
|
|
1638
|
-
const cfg = config?.affinityDynamics?.coefficient || {};
|
|
1639
|
-
const defaults = AFFINITY_DYNAMICS_DEFAULTS.coefficient;
|
|
1640
|
-
const base = Number.isFinite(cfg.base) ? cfg.base : defaults.base;
|
|
1641
|
-
const maxDrop = Math.max(
|
|
1642
|
-
0,
|
|
1643
|
-
Number.isFinite(cfg.maxDrop) ? cfg.maxDrop : defaults.maxDrop
|
|
1644
|
-
);
|
|
1645
|
-
const maxBoost = Math.max(
|
|
1646
|
-
0,
|
|
1647
|
-
Number.isFinite(cfg.maxBoost) ? cfg.maxBoost : defaults.maxBoost
|
|
1648
|
-
);
|
|
1649
|
-
const decayPerDay = Math.max(
|
|
1650
|
-
0,
|
|
1651
|
-
Number.isFinite(cfg.decayPerDay) ? cfg.decayPerDay : defaults.decayPerDay
|
|
1652
|
-
);
|
|
1653
|
-
const boostPerDay = Math.max(
|
|
1654
|
-
0,
|
|
1655
|
-
Number.isFinite(cfg.boostPerDay) ? cfg.boostPerDay : defaults.boostPerDay
|
|
1656
|
-
);
|
|
1657
|
-
const min = base - maxDrop;
|
|
1658
|
-
const max = base + maxBoost;
|
|
1659
|
-
return { base, maxDrop, maxBoost, decayPerDay, boostPerDay, min, max };
|
|
1660
|
-
}
|
|
1661
|
-
function summarizeActionEntries(rawEntries, windowMs, nowMs) {
|
|
1662
|
-
const fallback = {
|
|
1663
|
-
entries: [],
|
|
1664
|
-
counts: { increase: 0, decrease: 0 },
|
|
1665
|
-
total: 0
|
|
1666
|
-
};
|
|
1667
|
-
if (!Array.isArray(rawEntries)) return fallback;
|
|
1668
|
-
const cutoff = nowMs - windowMs;
|
|
1669
|
-
const entries = [];
|
|
1670
|
-
const counts = { increase: 0, decrease: 0 };
|
|
1671
|
-
for (const entry of rawEntries) {
|
|
1672
|
-
if (!entry) continue;
|
|
1673
|
-
const ts = Number(entry.timestamp);
|
|
1674
|
-
if (!Number.isFinite(ts) || ts < cutoff) continue;
|
|
1675
|
-
const normalizedAction = normalizeAction(entry.action);
|
|
1676
|
-
entries.push({ action: normalizedAction, timestamp: ts });
|
|
1677
|
-
counts[normalizedAction] += 1;
|
|
1678
|
-
}
|
|
1679
|
-
return { entries, counts, total: counts.increase + counts.decrease };
|
|
1680
|
-
}
|
|
1681
|
-
function appendActionEntry(entries, action, nowMs, maxEntries) {
|
|
1682
|
-
const next = Array.isArray(entries) ? [...entries] : [];
|
|
1683
|
-
next.push({ action: normalizeAction(action), timestamp: nowMs });
|
|
1684
|
-
if (next.length > maxEntries) next.splice(0, next.length - maxEntries);
|
|
1685
|
-
return next;
|
|
1686
|
-
}
|
|
1687
|
-
function computeShortTermReset() {
|
|
1688
|
-
return 0;
|
|
1689
|
-
}
|
|
1690
|
-
function dayNumber2(date) {
|
|
1691
|
-
return Math.floor(date.getTime() / 864e5);
|
|
1692
|
-
}
|
|
1693
|
-
function computeDailyStreak(previousStreak, lastInteractionAt, now) {
|
|
1694
|
-
const last = lastInteractionAt instanceof Date ? lastInteractionAt : null;
|
|
1695
|
-
const currentDay = dayNumber2(now);
|
|
1696
|
-
const previousDay = last ? dayNumber2(last) : null;
|
|
1697
|
-
if (previousDay === null) return 1;
|
|
1698
|
-
if (previousDay === currentDay) return Math.max(1, previousStreak || 1);
|
|
1699
|
-
if (previousDay === currentDay - 1)
|
|
1700
|
-
return Math.max(1, (previousStreak || 0) + 1);
|
|
1701
|
-
return 1;
|
|
1702
|
-
}
|
|
1703
|
-
function computeCoefficientValue(coefConfig, streak, lastInteractionAt, now, todayIncreaseCount = 0, todayDecreaseCount = 0) {
|
|
1704
|
-
const lastMs = lastInteractionAt instanceof Date ? lastInteractionAt.getTime() : null;
|
|
1705
|
-
const nowMs = now.getTime();
|
|
1706
|
-
const inactivityDays = lastMs ? Math.max(0, Math.floor((nowMs - lastMs) / 864e5)) : 0;
|
|
1707
|
-
const hasInteractedToday = inactivityDays === 0;
|
|
1708
|
-
const isPositiveDay = todayIncreaseCount > todayDecreaseCount;
|
|
1709
|
-
const isNegativeDay = todayDecreaseCount > todayIncreaseCount;
|
|
1710
|
-
let decayPenalty = 0;
|
|
1711
|
-
let streakBoost = 0;
|
|
1712
|
-
if (!hasInteractedToday || isNegativeDay) {
|
|
1713
|
-
if (!hasInteractedToday) {
|
|
1714
|
-
decayPenalty = Math.min(
|
|
1715
|
-
coefConfig.maxDrop,
|
|
1716
|
-
inactivityDays * coefConfig.decayPerDay
|
|
1717
|
-
);
|
|
1718
|
-
} else if (isNegativeDay) {
|
|
1719
|
-
decayPenalty = Math.min(coefConfig.maxDrop, coefConfig.decayPerDay);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
if (hasInteractedToday && isPositiveDay && streak > 0) {
|
|
1723
|
-
streakBoost = Math.min(
|
|
1724
|
-
coefConfig.maxBoost,
|
|
1725
|
-
Math.max(0, (Math.max(1, streak) - 1) * coefConfig.boostPerDay)
|
|
1726
|
-
);
|
|
1727
|
-
}
|
|
1728
|
-
const coefficient = clampFloat(
|
|
1729
|
-
coefConfig.base - decayPenalty + streakBoost,
|
|
1730
|
-
coefConfig.min,
|
|
1731
|
-
coefConfig.max
|
|
1732
|
-
);
|
|
1733
|
-
return { coefficient, decayPenalty, streakBoost, inactivityDays };
|
|
1734
|
-
}
|
|
1735
|
-
function composeState(longTerm, shortTerm, clampFn) {
|
|
1736
|
-
return {
|
|
1737
|
-
affinity: clampFn(longTerm),
|
|
1738
|
-
longTermAffinity: clampFn(longTerm),
|
|
1739
|
-
shortTermAffinity: Math.round(shortTerm)
|
|
1740
|
-
};
|
|
1741
|
-
}
|
|
1742
|
-
function formatActionCounts(counts) {
|
|
1743
|
-
const safe = counts || {};
|
|
1744
|
-
const increase = Number(safe.increase) || 0;
|
|
1745
|
-
const decrease = Number(safe.decrease) || 0;
|
|
1746
|
-
return `\u63D0\u5347 ${increase} / \u964D\u4F4E ${decrease}`;
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
1762
|
// src/services/message/history.ts
|
|
1750
1763
|
function createMessageHistory(options) {
|
|
1751
1764
|
const { ctx, config, log } = options;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chatluna-affinity",
|
|
3
3
|
"description": "ChatLuna Character 好感度系统,提供 {好感度}、{关系}、{黑名单} 变量与工具,并支持 XML 工具调用,仅支持 onebot 平台。",
|
|
4
|
-
"version": "0.3.0-beta.
|
|
4
|
+
"version": "0.3.0-beta.3",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
|
-
"
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"lib",
|
|
9
9
|
"dist",
|
|
@@ -43,20 +43,18 @@
|
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@koishijs/client": "^5.30.0",
|
|
46
|
-
"@types/node": "^
|
|
46
|
+
"@types/node": "^22.10.1",
|
|
47
47
|
"@vitejs/plugin-vue": "^6.0.2",
|
|
48
48
|
"rimraf": "^5.0.5",
|
|
49
49
|
"sass": "^1.77.0",
|
|
50
50
|
"tsup": "^8.0.0",
|
|
51
|
-
"typescript": "^5.
|
|
51
|
+
"typescript": "^5.7.2",
|
|
52
52
|
"vite": "^6.0.0"
|
|
53
53
|
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"koishi-plugin-chatluna": "*"
|
|
56
|
-
},
|
|
57
54
|
"scripts": {
|
|
58
55
|
"build": "tsup && vite build",
|
|
59
56
|
"watch": "tsup --watch",
|
|
60
|
-
"clean": "rimraf lib dist"
|
|
57
|
+
"clean": "rimraf lib dist",
|
|
58
|
+
"test": "node --test --test-name-pattern='.*' test/*.test.js"
|
|
61
59
|
}
|
|
62
60
|
}
|