Release beta 1.1.0 scan and duplicate fixes

This commit is contained in:
JWeBot Contributors
2026-10-16 17:14:41 +08:00
parent b1d8e4e8e7
commit 35ef82f14f
23 changed files with 217 additions and 37 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-config"
version = "1.0.5b1+1016"
version = "1.1.0b1+1016"
description = "Profile-based configuration compiler for JWeBot"
requires-python = ">=3.9"
dependencies = [
@@ -36,4 +36,4 @@ __all__ = [
"write_default_profile",
]
__version__ = "1.0.5b1+1016"
__version__ = "1.1.0b1+1016"
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-extension-host"
version = "1.0.5b1+1016"
version = "1.1.0b1+1016"
description = "Single-release, single-invocation process host for JWeBot extensions"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.0.5b1+1016",
"jwebot-kernel==1.0.5b1+1016",
"jwebot-sdk==1.1.0b1+1016",
"jwebot-kernel==1.1.0b1+1016",
]
[project.scripts]
@@ -16,4 +16,4 @@ __all__ = [
"process_request",
]
__version__ = "1.0.5b1+1016"
__version__ = "1.1.0b1+1016"
+4 -4
View File
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-kernel"
version = "1.0.5b1+1016"
version = "1.1.0b1+1016"
description = "Stable routing and extension authority for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-config==1.0.5b1+1016",
"jwebot-sdk==1.0.5b1+1016",
"jwebot-official-extensions==1.0.5b1+1016",
"jwebot-config==1.1.0b1+1016",
"jwebot-sdk==1.1.0b1+1016",
"jwebot-official-extensions==1.1.0b1+1016",
"tomli>=2; python_version < '3.11'",
]
@@ -107,4 +107,4 @@ __all__ = [
"verify_installed_release_signature",
]
__version__ = "1.0.5b1+1016"
__version__ = "1.1.0b1+1016"
@@ -104,6 +104,18 @@ MAX_EVENT_TEXT = 5_000
MAX_REPLY_CHARS = 900
MAX_CONTEXT_TURNS = 6
OCR_EVENT_SOURCES = frozenset({"ocr", "rapidocr-local"})
OCR_SEMANTIC_DUPLICATE_SECONDS = 8.0
OCR_RESOURCE_MUTATION_DUPLICATE_SECONDS = 75.0
OCR_RESOURCE_MUTATION_REASONS = frozenset(
{
"local_loan",
"local_primogem_wish",
"local_repay",
"local_scan_boost",
"local_taffy_say",
"local_transfer",
}
)
MAX_OUTBOX_ATTEMPTS = 3
DIRECT_CHAT_GENERATION_WORKERS = 2
DIRECT_API_SOCKET_TIMEOUT_SECONDS = 18.0
@@ -2985,6 +2997,85 @@ class Ledger:
).fetchall()
return [dict(row) for row in rows]
def clock_scan_ranking_all(
self,
group_fingerprint: str,
local_date: str,
) -> list[dict[str, Any]]:
group = bounded_text(group_fingerprint, limit=256)
people: dict[str, dict[str, Any]] = {}
for person in self.person_directory(group):
people[str(person["person_key"])] = {
"person_key": str(person["person_key"]),
"display_name": str(person["display_name"]),
"scan_count": 0,
}
with self.lock:
rows = self.connection.execute(
"""
SELECT person_key, display_name, scan_count
FROM clock_scan_scores
WHERE group_fingerprint = ? AND local_date = ?
""",
(group, local_date),
).fetchall()
for row in rows:
person_key = str(row["person_key"])
people[person_key] = {
"person_key": person_key,
"display_name": str(row["display_name"]),
"scan_count": int(row["scan_count"]),
}
people_list = list(people.values())
people_list.sort(
key=lambda item: (
-int(item["scan_count"]),
str(item["display_name"]).casefold(),
)
)
return people_list
def next_clock_scan_weights(
self,
group_fingerprint: str,
) -> list[dict[str, Any]]:
group = bounded_text(group_fingerprint, limit=256)
weights: dict[str, dict[str, Any]] = {}
for person in self.person_directory(group):
weights[str(person["person_key"])] = {
"person_key": str(person["person_key"]),
"display_name": str(person["display_name"]),
"weight": 1,
}
for canonical_name, scan_label in CLOCK_SCAN_TARGETS:
person_key = person_scope_key(group, canonical_name)
weights.setdefault(
person_key,
{
"person_key": person_key,
"display_name": scan_label,
"weight": 1,
},
)
for person_key, boost in self.active_scan_boost_targets(group).items():
entry = weights.setdefault(
person_key,
{
"person_key": person_key,
"display_name": str(boost["display_name"]),
"weight": 1,
},
)
entry["weight"] += int(boost.get("extra_weight", 0))
weight_list = list(weights.values())
weight_list.sort(
key=lambda item: (
-int(item["weight"]),
str(item["display_name"]).casefold(),
)
)
return weight_list
def record_dice_challenge_achievement(
self,
*,
@@ -6979,12 +7070,18 @@ class EdgeApplication:
existing_row = self.ledger.row(event_id) if event_id else None
semantic_duplicate = None
if existing_row is None and is_ocr_event(event):
duplicate_window = (
OCR_RESOURCE_MUTATION_DUPLICATE_SECONDS
if reason in OCR_RESOURCE_MUTATION_REASONS
else OCR_SEMANTIC_DUPLICATE_SECONDS
)
semantic_duplicate = self.ledger.recent_semantic_duplicate(
group_fingerprint=group_id,
sender=str(event.get("sender", "")),
question=question,
route=route,
route_reason=reason,
within_seconds=duplicate_window,
)
if semantic_duplicate is not None:
self.telemetry.elapsed(
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-official-extensions"
version = "1.0.5b1+1016"
version = "1.1.0b1+1016"
description = "Reviewed local command adapters and broker implementation for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.0.5b1+1016",
"jwebot-sdk==1.1.0b1+1016",
]
[tool.setuptools.packages.find]
@@ -90,4 +90,4 @@ __all__ = [
"render_feature_list",
]
__version__ = "1.0.5b1+1016"
__version__ = "1.1.0b1+1016"
@@ -246,17 +246,25 @@ class LocalCommandEngine:
def scan_ranking(self, row: dict[str, Any]) -> str:
local_date = datetime.now(BEIJING_TIMEZONE).date().isoformat()
ranking = self.ledger.clock_scan_ranking(
str(row["group_fingerprint"]),
group = str(row["group_fingerprint"])
ranking = self.ledger.clock_scan_ranking_all(
group,
local_date,
)
weights = self.ledger.next_clock_scan_weights(
str(row["group_fingerprint"]),
)
if not ranking:
return "北京时间今天还没有已确认送达的扫码记录"
return "北京时间今天还没有可展示的扫码候选"
listing = ";".join(
f"{index}. {entry['display_name']} {entry['scan_count']} 次"
for index, entry in enumerate(ranking, start=1)
)
return f"北京时间今日扫码排行:{listing}"
weight_listing = ";".join(
f"{entry['display_name']} {entry['weight']}"
for entry in weights
)
return f"北京时间今日扫码排行:{listing}\n下一小时扫码权重:{weight_listing}"
def repeat_ranking(self, row: dict[str, Any]) -> str:
self.ledger.bootstrap_repeat_history()
@@ -692,7 +692,9 @@ class PlayerGames:
lines = [
(
f"{player_label}:{expired}当前摩拉 {account['balance']};"
f"原石 {account['primogems']} 个;{loan_text}"
f"原石 {account['primogems']} 个;"
f"扫码概率券 {account['scan_boost_tickets']} 张;"
f"{loan_text}"
),
(
f"21点 {state};已结算胜 {account['wins']} / "
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-sdk"
version = "1.0.5b1+1016"
version = "1.1.0b1+1016"
description = "Typed, capability-limited extension API for JWeBot plugins"
requires-python = ">=3.9"
dependencies = []
@@ -38,4 +38,4 @@ __all__ = [
"SingleGroupContext",
]
__version__ = "1.0.5b1+1016"
__version__ = "1.1.0b1+1016"