Release beta 1.2.6.1019
check / local-gate (push) Failing after 2m29s

This commit is contained in:
JWeBot Contributors
2026-10-19 22:29:36 +08:00
parent 8670745235
commit ed2fd0200f
19 changed files with 165 additions and 44 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-config"
version = "1.2.5b1+1019"
version = "1.2.6b1+1019"
description = "Profile-based configuration compiler for JWeBot"
requires-python = ">=3.9"
dependencies = [
@@ -36,4 +36,4 @@ __all__ = [
"write_default_profile",
]
__version__ = "1.2.5b1+1019"
__version__ = "1.2.6b1+1019"
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-extension-host"
version = "1.2.5b1+1019"
version = "1.2.6b1+1019"
description = "Single-release, single-invocation process host for JWeBot extensions"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.2.5b1+1019",
"jwebot-kernel==1.2.5b1+1019",
"jwebot-sdk==1.2.6b1+1019",
"jwebot-kernel==1.2.6b1+1019",
]
[project.scripts]
@@ -16,4 +16,4 @@ __all__ = [
"process_request",
]
__version__ = "1.2.5b1+1019"
__version__ = "1.2.6b1+1019"
+4 -4
View File
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-kernel"
version = "1.2.5b1+1019"
version = "1.2.6b1+1019"
description = "Stable routing and extension authority for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-config==1.2.5b1+1019",
"jwebot-sdk==1.2.5b1+1019",
"jwebot-official-extensions==1.2.5b1+1019",
"jwebot-config==1.2.6b1+1019",
"jwebot-sdk==1.2.6b1+1019",
"jwebot-official-extensions==1.2.6b1+1019",
"tomli>=2; python_version < '3.11'",
]
@@ -107,4 +107,4 @@ __all__ = [
"verify_installed_release_signature",
]
__version__ = "1.2.5b1+1019"
__version__ = "1.2.6b1+1019"
@@ -166,6 +166,44 @@ TRIVIA_HISTORY_KEY = "trivia_quiz_history"
TRIVIA_ANSWER_WINDOW_MINUTES = 5
TRIVIA_QUIZ_PROBABILITY_PERCENT = 75
TRIVIA_RECENT_BASE_LIMIT = 24
TRIVIA_TOPIC_NAMES = (
"反恐精英",
"顶点英雄",
"守望先锋",
"英雄联盟",
"少女乐团派对",
"韩流",
"原神",
)
TRIVIA_TOPIC_ALIASES = {
"反恐精英": "反恐精英",
"反恐": "反恐精英",
"cs": "反恐精英",
"cs2": "反恐精英",
"csgo": "反恐精英",
"顶点英雄": "顶点英雄",
"顶点": "顶点英雄",
"apex": "顶点英雄",
"守望先锋": "守望先锋",
"守望": "守望先锋",
"ow": "守望先锋",
"overwatch": "守望先锋",
"英雄联盟": "英雄联盟",
"联盟": "英雄联盟",
"lol": "英雄联盟",
"leagueoflegends": "英雄联盟",
"少女乐团派对": "少女乐团派对",
"邦邦": "少女乐团派对",
"gbp": "少女乐团派对",
"girlsbandparty": "少女乐团派对",
"bangdream": "少女乐团派对",
"韩流": "韩流",
"韩国流行音乐": "韩流",
"kpop": "韩流",
"原神": "原神",
"genshin": "原神",
"genshinimpact": "原神",
}
BEIJING_TIMEZONE = ZoneInfo("Asia/Shanghai")
ACKNOWLEDGEMENT = "已收到,正在处理中喵"
STEAM_ACKNOWLEDGEMENT = "Steam 查询 [■□□] 正在读取公开数据"
@@ -360,6 +398,21 @@ TRIVIA_FACTS: tuple[tuple[str, str, str, str, tuple[str, str, str], str, int], .
("lol-zac", "英雄联盟", "扎克名字常被解释为什么缩写?", "祖安无定形战斗体", ("祖安奥术核心", "时间装置自动体", "祖安酸液生物"), "扎克的名字常被当作祖安无定形战斗体的缩写梗。", 4),
("lol-kindred", "英雄联盟", "永猎双子由哪两个化身组成?", "羊灵和狼灵", ("乌鸦和雄鹿", "狐狸和猫头鹰", "太阳和月亮"), "永猎双子是羊灵与狼灵两个死亡化身。", 2),
("lol-ryze", "英雄联盟", "瑞兹长期收集并封存的危险物是什么?", "世界符文", ("暗裔武器", "海克斯核心", "虚空碎片"), "瑞兹的主线目标是阻止世界符文失控。", 3),
("gbp-random-star", "少女乐团派对", "户山香澄使用的星形吉他昵称是什么?", "随机星", ("流星号", "闪耀心", "星光鸟"), "户山香澄的标志性星形吉他昵称是随机星。", 4),
("gbp-hikawa-sisters", "少女乐团派对", "冰川双子里姐姐是谁?", "冰川纱夜", ("冰川日菜", "丸山彩", "今井莉莎"), "冰川纱夜是姐姐,冰川日菜是妹妹。", 3),
("gbp-aya-idol", "少女乐团派对", "丸山彩所在乐队最核心的组合定位是?", "偶像乐队", ("幼驯染摇滚", "哥特交响", "欢乐马戏"), "丸山彩所在组合以偶像乐队定位为核心。", 3),
("gbp-yukina-father", "少女乐团派对", "凑友希那坚持音乐的家庭原因主要和谁有关?", "父亲", ("姐姐", "祖母", "老师"), "凑友希那对音乐的执着,很大一部分和父亲的经历有关。", 4),
("gbp-tsugumi-cafe", "少女乐团派对", "羽泽鸫家里经营的店更接近什么?", "咖啡店", ("唱片店", "花店", "乐器店"), "羽泽鸫家经营咖啡店,她也经常帮忙。", 3),
("kpop-snsd-debut", "韩流", "少女时代的出道曲是哪首?", "再次重逢的世界", ("说出你的愿望", "哦", "狮心"), "少女时代的出道曲是再次重逢的世界。", 4),
("kpop-redvelvet-leader", "韩流", "红贝贝的队长是谁?", "裴柱现", ("姜涩琪", "孙胜完", "朴秀荣"), "红贝贝的队长是裴柱现。", 3),
("kpop-newjeans-fandom", "韩流", "新牛仔的官方粉丝名中文常译为什么?", "兔子", ("星星", "花园", "钥匙"), "新牛仔的官方粉丝名常译作兔子。", 4),
("kpop-first-win", "韩流", "歌谣节目里常说的“一位”通常指什么?", "当期第一名", ("出道舞台", "安可失败", "投票资格"), "一位通常指某个歌谣节目当期排名第一。", 2),
("kpop-lightstick", "韩流", "韩流演唱会里粉丝常用来应援的发光道具叫什么?", "应援棒", ("舞台牌", "投票券", "签售卡"), "应援棒是韩流现场应援里很常见的发光道具。", 2),
("genshin-barbatos", "原神", "蒙德风神的真实魔神名是?", "巴巴托斯", ("摩拉克斯", "巴尔泽布", "布耶尔"), "蒙德风神温迪对应的魔神名是巴巴托斯。", 3),
("genshin-morax", "原神", "璃月岩王帝君的魔神名是?", "摩拉克斯", ("巴巴托斯", "厄歌莉娅", "布耶尔"), "岩王帝君钟离对应的魔神名是摩拉克斯。", 3),
("genshin-ei", "原神", "稻妻一心净土里的真正主人是谁?", "雷电影", ("雷电真", "八重神子", "九条裟罗"), "一心净土里的真正主人是雷电影。", 4),
("genshin-nahida-title", "原神", "纳西妲作为神明对应的称号是?", "小吉祥草王", ("大慈树王", "尘世闲游", "正义之神"), "纳西妲在须弥被称为小吉祥草王。", 3),
("genshin-neuvillette", "原神", "枫丹最高审判官是谁?", "那维莱特", ("莱欧斯利", "芙宁娜", "克洛琳德"), "那维莱特是枫丹的最高审判官。", 3),
)
TRIVIA_TEMPLATES = (
"【{domain} 冷知识】{prompt}",
@@ -378,12 +431,32 @@ def trivia_reward(rarity: int) -> int:
return 20 + max(1, min(5, int(rarity))) * 30
def trivia_topic_key(value: object) -> str:
return re.sub(
r"[\s'’`·・_\-::.。!!??]+",
"",
str(value or "").casefold(),
)
def canonical_trivia_topic(value: object) -> str | None:
topic = trivia_topic_key(value)
if not topic:
return None
return TRIVIA_TOPIC_ALIASES.get(topic)
def supported_trivia_topics_message() -> str:
return "支持主题:" + "、".join(TRIVIA_TOPIC_NAMES)
@lru_cache(maxsize=1)
def trivia_question_bank() -> tuple[dict[str, object], ...]:
questions: list[dict[str, object]] = [
{
**question,
"base_id": str(question["id"]),
"topic": canonical_trivia_topic(question.get("domain")) or str(question["domain"]),
"rarity": int(question.get("rarity", 4)),
"reward": trivia_reward(int(question.get("rarity", 4))),
}
@@ -399,6 +472,7 @@ def trivia_question_bank() -> tuple[dict[str, object], ...]:
"id": f"{base_id}-{variant + 1}",
"base_id": base_id,
"domain": domain,
"topic": canonical_trivia_topic(domain) or domain,
"question": template.format(domain=domain, prompt=prompt),
"options": rotated,
"answer": answer_label,
@@ -6764,10 +6838,20 @@ class HourlyBroadcastEngine:
*,
group: str,
local_now: datetime,
topic: str | None = None,
) -> dict[str, object]:
bank = trivia_question_bank()
bank = tuple(
question
for question in trivia_question_bank()
if topic is None or str(question.get("topic")) == topic
)
if not bank:
raise LocalCommandError("这个主题还没有题喵\n" + supported_trivia_topics_message())
recent = set(self.trivia_recent_base_ids(group))
seed = f"{group}|{local_now.date().isoformat()}|{local_now.hour:02d}|trivia"
seed = (
f"{group}|{local_now.date().isoformat()}|"
f"{local_now.hour:02d}|trivia|{topic or 'all'}"
)
start = deterministic_int(seed, 0, len(bank) - 1)
for offset in range(len(bank)):
candidate = bank[(start + offset) % len(bank)]
@@ -6783,8 +6867,15 @@ class HourlyBroadcastEngine:
raise LocalCommandError("冷门问答题库选项无效")
rarity = max(1, min(5, int(question.get("rarity", 3))))
reward = max(1, min(500, int(question.get("reward", trivia_reward(rarity)))))
topic = normalize_text(question.get("topic") or question.get("domain"))
heading = f"冷门知识问答(冷门度 {rarity}/5,限时5分钟,答对 +{reward} 摩拉)"
if topic:
heading = (
f"冷门知识问答(主题:{topic},冷门度 {rarity}/5,"
f"限时5分钟,答对 +{reward} 摩拉)"
)
lines = [
f"冷门知识问答(冷门度 {rarity}/5,限时5分钟,答对 +{reward} 摩拉)",
heading,
str(question.get("question", "")),
]
lines.extend(
@@ -6799,8 +6890,13 @@ class HourlyBroadcastEngine:
*,
group: str,
local_now: datetime,
topic: str | None = None,
) -> str:
question = self.select_trivia_question(group=group, local_now=local_now)
question = self.select_trivia_question(
group=group,
local_now=local_now,
topic=topic,
)
message = self.render_trivia_message(question)
expires_at = (
local_now + timedelta(minutes=TRIVIA_ANSWER_WINDOW_MINUTES)
@@ -6811,6 +6907,7 @@ class HourlyBroadcastEngine:
{
"question_id": str(question["id"]),
"base_id": str(question.get("base_id") or question["id"]),
"topic": str(question.get("topic") or question.get("domain") or ""),
"question": str(question["question"]),
"options": list(question["options"]),
"answer": str(question["answer"]),
@@ -6828,9 +6925,13 @@ class HourlyBroadcastEngine:
self,
*,
group: str,
topic_name: str = "",
now: datetime | None = None,
) -> str:
local_now = self.in_beijing_timezone(now)
topic = canonical_trivia_topic(topic_name)
if normalize_text(topic_name) and topic is None:
return supported_trivia_topics_message()
active = self.ledger.local_game(group, TRIVIA_GAME_KEY)
if active:
try:
@@ -6839,7 +6940,11 @@ class HourlyBroadcastEngine:
except (TypeError, ValueError):
return "冷门问答状态坏了喵"
self.ledger.clear_local_game(group, TRIVIA_GAME_KEY)
return self.start_trivia_question(group=group, local_now=local_now)
return self.start_trivia_question(
group=group,
local_now=local_now,
topic=topic,
)
def due_trivia_broadcast(
self,
@@ -8107,10 +8212,11 @@ class EdgeApplication:
}
if decision.execution_path is ExecutionPath.LOCAL_COMMAND:
try:
command_kind = local_command_kind(str(row["question"]))
command_kind, command_arguments = local_command_parts(str(row["question"]))
reply = (
self.clock.force_trivia_message(
group=str(row["group_fingerprint"])
group=str(row["group_fingerprint"]),
topic_name=command_arguments,
)
if command_kind == "trivia_start"
else
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-official-extensions"
version = "1.2.5b1+1019"
version = "1.2.6b1+1019"
description = "Reviewed local command adapters and broker implementation for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.2.5b1+1019",
"jwebot-sdk==1.2.6b1+1019",
]
[tool.setuptools.packages.find]
@@ -90,4 +90,4 @@ __all__ = [
"render_feature_list",
]
__version__ = "1.2.5b1+1019"
__version__ = "1.2.6b1+1019"
@@ -153,8 +153,8 @@ DIRECT_KERNEL_COMMANDS = (
command_kinds=("deepseek_balance",),
),
KernelCommandDescriptor(
description="手动触发冷门知识问答",
help_entries=("/知识问答",),
description="冷门问答",
help_entries=("/知识问答 [主题]",),
command_kinds=("trivia_start",),
),
)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-sdk"
version = "1.2.5b1+1019"
version = "1.2.6b1+1019"
description = "Typed, capability-limited extension API for JWeBot plugins"
requires-python = ">=3.9"
dependencies = []
@@ -38,4 +38,4 @@ __all__ = [
"SingleGroupContext",
]
__version__ = "1.2.5b1+1019"
__version__ = "1.2.6b1+1019"