diff --git a/CHANGELOG.md b/CHANGELOG.md index 579fbe0..d24d1a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## beta 1.2.8.1019 - 2026-10-19 22:49:30 + +- 冷门知识问答题库整体重写:改为更偏游戏内机制、数值、版本和活动细节的深度题。 +- Trivia display now allows necessary proper nouns while preferring + Chinese-first names such as 中文(English) when a common translation exists. + ## beta 1.2.7.1019 - 2026-10-19 22:37:40 - 冷门知识问答新增缪斯学园偶像和我的世界题库,并支持 LoveLive 与 Minecraft 主题别名。 diff --git a/README.md b/README.md index 468e4b7..48b550d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ JWeBot 是运行于 Linux 的单群微信自动回复系统。它通过本地 OC 观察选定的微信窗口,将消息写入持久化 Edge 账本,调用经过审核的命令插件, 并通过带视觉确认的 GUI 发送链路回复。 -当前版本:`beta 1.2.7.1019`,更新时间:2026-10-19 22:37:40。 +当前版本:`beta 1.2.8.1019`,更新时间:2026-10-19 22:49:30。 1.0 Beta 收口了当前稳定功能:本地命令插件、人物与上下文索引、 Steam 状态与时长查询、虚拟摩拉游戏、多人彩票、21 点、CS Major @@ -270,10 +270,10 @@ visually confirmed GUI bridge. Current version: ```text -beta 1.2.7.1019 +beta 1.2.8.1019 ``` -Updated: 2026-10-19 22:37:40. +Updated: 2026-10-19 22:49:30. The 1.0 Beta baseline consolidates the stable local command set, person and context indexes, Steam presence/playtime queries, virtual coin games, diff --git a/VERSION b/VERSION index 19a1444..426b645 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -beta 1.2.7.1019 +beta 1.2.8.1019 diff --git a/docs/command-catalog.md b/docs/command-catalog.md index dbeb46a..509ef91 100644 --- a/docs/command-catalog.md +++ b/docs/command-catalog.md @@ -1,6 +1,6 @@ # JWeBot Command Catalog -Current baseline: `beta 1.2.7.1019`. +Current baseline: `beta 1.2.8.1019`. This catalog records the reviewed commands shipped with the built-in local extensions. Runtime ownership is frozen at startup from the generated diff --git a/packages/jwebot-config/pyproject.toml b/packages/jwebot-config/pyproject.toml index 0274ea2..8c91958 100644 --- a/packages/jwebot-config/pyproject.toml +++ b/packages/jwebot-config/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "jwebot-config" -version = "1.2.7b1+1019" +version = "1.2.8b1+1019" description = "Profile-based configuration compiler for JWeBot" requires-python = ">=3.9" dependencies = [ diff --git a/packages/jwebot-config/src/jwebot_config/__init__.py b/packages/jwebot-config/src/jwebot_config/__init__.py index 2cc32b4..f61f135 100644 --- a/packages/jwebot-config/src/jwebot_config/__init__.py +++ b/packages/jwebot-config/src/jwebot_config/__init__.py @@ -36,4 +36,4 @@ __all__ = [ "write_default_profile", ] -__version__ = "1.2.7b1+1019" +__version__ = "1.2.8b1+1019" diff --git a/packages/jwebot-extension-host/pyproject.toml b/packages/jwebot-extension-host/pyproject.toml index e21a4bc..69231ec 100644 --- a/packages/jwebot-extension-host/pyproject.toml +++ b/packages/jwebot-extension-host/pyproject.toml @@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "jwebot-extension-host" -version = "1.2.7b1+1019" +version = "1.2.8b1+1019" description = "Single-release, single-invocation process host for JWeBot extensions" requires-python = ">=3.9" dependencies = [ - "jwebot-sdk==1.2.7b1+1019", - "jwebot-kernel==1.2.7b1+1019", + "jwebot-sdk==1.2.8b1+1019", + "jwebot-kernel==1.2.8b1+1019", ] [project.scripts] diff --git a/packages/jwebot-extension-host/src/jwebot_extension_host/__init__.py b/packages/jwebot-extension-host/src/jwebot_extension_host/__init__.py index b5962b3..0fa16b7 100644 --- a/packages/jwebot-extension-host/src/jwebot_extension_host/__init__.py +++ b/packages/jwebot-extension-host/src/jwebot_extension_host/__init__.py @@ -16,4 +16,4 @@ __all__ = [ "process_request", ] -__version__ = "1.2.7b1+1019" +__version__ = "1.2.8b1+1019" diff --git a/packages/jwebot-kernel/pyproject.toml b/packages/jwebot-kernel/pyproject.toml index e30ff15..907a291 100644 --- a/packages/jwebot-kernel/pyproject.toml +++ b/packages/jwebot-kernel/pyproject.toml @@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta" [project] name = "jwebot-kernel" -version = "1.2.7b1+1019" +version = "1.2.8b1+1019" description = "Stable routing and extension authority for JWeBot" requires-python = ">=3.9" dependencies = [ - "jwebot-config==1.2.7b1+1019", - "jwebot-sdk==1.2.7b1+1019", - "jwebot-official-extensions==1.2.7b1+1019", + "jwebot-config==1.2.8b1+1019", + "jwebot-sdk==1.2.8b1+1019", + "jwebot-official-extensions==1.2.8b1+1019", "tomli>=2; python_version < '3.11'", ] diff --git a/packages/jwebot-kernel/src/jwebot_kernel/__init__.py b/packages/jwebot-kernel/src/jwebot_kernel/__init__.py index 6b04f75..a6c06c5 100644 --- a/packages/jwebot-kernel/src/jwebot_kernel/__init__.py +++ b/packages/jwebot-kernel/src/jwebot_kernel/__init__.py @@ -107,4 +107,4 @@ __all__ = [ "verify_installed_release_signature", ] -__version__ = "1.2.7b1+1019" +__version__ = "1.2.8b1+1019" diff --git a/packages/jwebot-kernel/src/jwebot_kernel/edge_runtime.py b/packages/jwebot-kernel/src/jwebot_kernel/edge_runtime.py index 32b3a7a..d907043 100644 --- a/packages/jwebot-kernel/src/jwebot_kernel/edge_runtime.py +++ b/packages/jwebot-kernel/src/jwebot_kernel/edge_runtime.py @@ -277,6 +277,9 @@ TAFFY_CHAT_STYLE_NOTE = ( "不要说自己只是 AI、机器人、语言模型,不要写能力边界、免责声明、" "自我介绍或“不能凭空给自己打分”这类自证。" "长回复要拆成短句,别一句话塞满。" + "如果上一轮你在追问“比什么/啥意思/谁啊”等澄清问题," + "当前用户只回一个短词或短句时,优先当作对这个追问的回答继续聊。" + "不要因为群里有冷门问答就把普通闲聊引导成“/回答 A”。" ) CHAT_REPLY_REDUNDANT_LINE = re.compile( r"(?:" @@ -290,6 +293,10 @@ CHAT_REPLY_REDUNDANT_LINE = re.compile( r")", re.IGNORECASE, ) +CHAT_REPLY_TRIVIA_HINT = re.compile( + r"[,,。;;\s]*(?:做题.{0,12}/回答\s*[A-D]|/回答\s*[A-D].{0,12}(?:答题|做题)).*$", + re.IGNORECASE, +) UNKNOWN_CLARIFICATION_PATTERNS = ( re.compile( r"(?P[\w\u4e00-\u9fff]{1,24}?)(?:是|算是|叫)?" @@ -314,132 +321,62 @@ SCAN_BOOST_PITY_MISS_LIMIT = 2 STEAM_GROUP_ROSTER: tuple[dict[str, object], ...] = () PERSON_ALIAS_MIGRATION_VERSION = "person-aliases-empty" PROFILE_ALIAS_REPAIR_CANONICALS: frozenset[str] = frozenset() -TRIVIA_QUESTIONS: tuple[dict[str, object], ...] = ( - { - "id": "cs2-smoke-he", - "domain": "反恐精英", - "question": "反恐精英2 里哪种投掷物可以把烟雾短暂炸开一个缺口?", - "options": ("燃烧弹", "高爆手雷", "诱饵弹", "闪光弹"), - "answer": "B", - "explanation": "反恐精英2 的体积烟会被高爆手雷短暂驱散,子弹也能打出小洞。", - }, - { - "id": "csgo-danger-zone", - "domain": "反恐精英", - "question": "反恐精英:全球攻势最早的危险区域模式地图叫什么?", - "options": ("黑场", "玄武岩", "突破", "阿努比斯"), - "answer": "A", - "explanation": "危险区域模式随黑场首发,后来才有锡洛科等地图。", - }, - { - "id": "apex-ash-name", - "domain": "顶点英雄", - "question": "顶点英雄里艾许变成机械仿生人之前的人类名字是?", - "options": ("艾蜜莉·帕凯特", "阿什莉·里德", "玛丽·萨默斯", "安妮塔·威廉姆斯"), - "answer": "B", - "explanation": "艾许的人类身份是阿什莉·里德博士,和地平线的过去有关。", - }, - { - "id": "apex-horizon-son", - "domain": "顶点英雄", - "question": "顶点英雄里地平线一直想回去见到的儿子叫什么?", - "options": ("牛顿", "艾略特", "杰克逊", "医疗无人机"), - "answer": "A", - "explanation": "地平线的儿子叫牛顿,名字也呼应了她的科学家设定。", - }, - { - "id": "overwatch-sigma-name", - "domain": "守望先锋", - "question": "守望先锋里西格玛的本名是?", - "options": ("杰米森·福克斯", "西布伦·德·柯伊伯", "泰哈撒·孟达塔", "阿坎德·奥贡迪穆"), - "answer": "B", - "explanation": "西格玛的本名是西布伦·德·柯伊伯,事故前是天体物理学家。", - }, - { - "id": "overwatch-zen-title", - "domain": "守望先锋", - "question": "禅雅塔名字前常见的“泰哈撒”更接近什么?", - "options": ("家族姓氏", "僧侣称号", "武器型号", "出生地名"), - "answer": "B", - "explanation": "泰哈撒是香巴里僧侣相关称号,不是普通意义的姓。", - }, - { - "id": "lol-ivern-cruel", - "domain": "英雄联盟", - "question": "英雄联盟里艾翁成为绿树朋友前曾被称为什么?", - "options": ("残忍者艾翁", "迷失者艾翁", "沉默者艾翁", "初始者艾翁"), - "answer": "A", - "explanation": "艾翁过去是残酷的战士,后来在神树事件后完全转变。", - }, - { - "id": "lol-aurelion-crown", - "domain": "英雄联盟", - "question": "奥瑞利安·索尔被巨神族控制主要靠什么东西束缚?", - "options": ("星界锁链", "一顶冠冕", "暮光长矛", "世界符文"), - "answer": "B", - "explanation": "巨神族用冠冕诱骗并束缚了奥瑞利安·索尔,这也是他怨气来源之一。", - }, -) +TRIVIA_QUESTIONS: tuple[dict[str, object], ...] = () TRIVIA_FACTS: tuple[tuple[str, str, str, str, tuple[str, str, str], str, int], ...] = ( - ("cs-zeus", "反恐精英", "哪件装备是一次性近距离电击武器?", "宙斯电击枪", ("轻型手枪", "连喷霰弹枪", "新星霰弹枪"), "宙斯电击枪命中后通常只能打一发,是反恐精英里很有梗的电击武器。", 3), - ("cs-defuse-kit", "反恐精英", "哪件道具能缩短防守方拆包时间?", "拆弹钳", ("防弹衣", "救援套装", "战术盾"), "拆弹钳能把拆包时间从 10 秒缩短到 5 秒。", 2), - ("cs-blacksite", "反恐精英", "反恐精英:全球攻势危险区域模式首发地图是哪张?", "黑场", ("锡洛科", "余烬", "玄武岩"), "黑场是危险区域模式上线时的首发地图。", 4), - ("cs-he-smoke", "反恐精英", "反恐精英2 里能短暂驱散体积烟的爆炸物是?", "高爆手雷", ("燃烧弹", "诱饵弹", "闪光弹"), "反恐精英2 的体积烟会被高爆手雷短暂炸开缺口。", 4), - ("cs-subtick", "反恐精英", "反恐精英2 官方重点宣传的输入结算机制叫?", "子刻输入", ("观战电视", "全景界面", "优先状态"), "反恐精英2 用子刻输入记录动作发生时刻,和传统刷新刻观感不同。", 3), - ("cs-office", "反恐精英", "办公室在反恐精英系列里属于哪类经典模式地图?", "人质救援", ("爆破", "军备竞赛", "死亡竞赛"), "办公室是经典人质救援地图,不是拆包图。", 2), - ("cs-cache", "反恐精英", "死城之谜的主题环境最接近哪个区域?", "切尔诺贝利周边", ("威尼斯水城", "摩洛哥集市", "月球基地"), "死城之谜的视觉主题来自切尔诺贝利和普里皮亚季工业区域。", 4), - ("apex-ash", "顶点英雄", "艾许成为机械仿生人前的人类名字是?", "阿什莉·里德", ("艾蜜莉·帕凯特", "玛丽·萨默斯", "安妮塔·威廉姆斯"), "艾许的旧身份是阿什莉·里德博士。", 4), - ("apex-horizon", "顶点英雄", "地平线一直想回去见到的儿子叫什么?", "牛顿", ("艾略特", "杰克逊", "密客"), "牛顿是地平线的儿子。", 3), - ("apex-crypto", "顶点英雄", "密客的本名是?", "朴泰俊", ("奥克塔维奥·席尔瓦", "沃尔特·菲茨罗伊", "马科阿·直布罗陀"), "密客的本名是朴泰俊。", 3), - ("apex-caustic", "顶点英雄", "腐蚀的本名是?", "亚历山大·诺克斯", ("艾略特·威特", "奥比·艾多拉西姆", "阿杰·切"), "腐蚀是亚历山大·诺克斯,背景里是毒气科学家。", 3), - ("apex-wattson", "顶点英雄", "华森的本名是?", "娜塔莉·帕凯特", ("洛芭·安德拉德", "玛丽·萨默斯", "安妮塔·威廉姆斯"), "华森是娜塔莉·帕凯特,和竞技场电力系统有关。", 3), - ("apex-fuse", "顶点英雄", "暴雷的本名是?", "沃尔特·菲茨罗伊", ("卡莱布·克罗斯", "艾略特·威特", "朴泰俊"), "暴雷的本名是沃尔特·菲茨罗伊。", 3), - ("apex-seer", "顶点英雄", "希尔的本名是?", "奥比·艾多拉西姆", ("马科阿·直布罗陀", "奥克塔维奥·席尔瓦", "杰克逊·威廉姆斯"), "希尔的本名是奥比·艾多拉西姆。", 4), - ("overwatch-sigma", "守望先锋", "西格玛的本名是?", "西布伦·德·柯伊伯", ("阿坎德·奥贡迪穆", "杰米森·福克斯", "马可·拉特利奇"), "西格玛是西布伦·德·柯伊伯,事故前是天体物理学家。", 3), - ("overwatch-doomfist", "守望先锋", "末日铁拳的本名是?", "阿坎德·奥贡迪穆", ("泰哈撒·禅雅塔", "加布里埃尔·雷耶斯", "尼兰·普鲁克萨玛尼"), "末日铁拳的本名是阿坎德·奥贡迪穆。", 3), - ("overwatch-junkrat", "守望先锋", "狂鼠的本名是?", "杰米森·福克斯", ("马可·拉特利奇", "科尔·卡西迪", "卢西奥·科雷亚·多斯桑托斯"), "狂鼠的本名是杰米森·福克斯。", 2), - ("overwatch-roadhog", "守望先锋", "路霸的本名是?", "马可·拉特利奇", ("杰米森·福克斯", "巴蒂斯特·奥古斯丁", "西布伦·德·柯伊伯"), "路霸的本名是马可·拉特利奇。", 2), - ("overwatch-bastion", "守望先锋", "堡垒的机体型号更接近哪一个?", "五十四型堡垒攻城机", ("韩国兔机甲", "七千型掠夺者", "十五型防御机"), "堡垒属于五十四型攻城自动机。", 5), - ("overwatch-ramattra", "守望先锋", "拉玛刹领导的组织是?", "归零者", ("黑爪", "守望先锋", "费斯卡集团"), "拉玛刹是归零者的核心领袖。", 3), - ("lol-ivern", "英雄联盟", "艾翁转变前曾被称为什么?", "残忍者艾翁", ("迷失者艾翁", "初始者艾翁", "沉默者艾翁"), "艾翁原本是残酷战士,后来因神树事件转变。", 4), - ("lol-aurelion", "英雄联盟", "奥瑞利安·索尔被巨神族控制主要靠什么?", "一顶冠冕", ("世界符文", "暮光长矛", "暗裔剑"), "巨神族用冠冕束缚了奥瑞利安·索尔。", 4), - ("lol-swain", "英雄联盟", "斯维因体内或身边关联的恶魔名字是?", "拉姆", ("塔姆", "伊芙琳", "魔腾"), "斯维因与秘密恶魔拉姆绑定。", 5), - ("lol-jhin", "英雄联盟", "烬的全名是?", "卡达·烬", ("影流凯隐", "杰里柯·斯维因", "托拜厄斯·菲利克斯"), "烬的名字是卡达·烬。", 3), - ("lol-rengar", "英雄联盟", "雷恩加尔属于哪个瓦斯塔亚部族?", "基拉什", ("玛莱", "洛特兰", "奥维卡特"), "雷恩加尔来自基拉什部族。", 5), - ("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), - ("lovelive-homura", "缪斯学园偶像", "高坂穗乃果家里经营的店主要卖什么?", "和果子", ("拉面", "唱片", "可丽饼"), "高坂穗乃果家经营和果子店,店名是穗村。", 3), - ("lovelive-nico-catchphrase", "缪斯学园偶像", "矢泽妮可最有代表性的招呼语是哪一句?", "妮可妮可妮", ("哈拉秀", "加油露比", "全力前进"), "矢泽妮可的标志性口号是妮可妮可妮。", 2), - ("lovelive-kotori-mother", "缪斯学园偶像", "南小鸟的母亲在学校里是什么身份?", "理事长", ("学生会长", "音乐老师", "校医"), "南小鸟的母亲是音乃木坂学院理事长。", 4), - ("lovelive-eli-roots", "缪斯学园偶像", "绚濑绘里常被提到的血统和哪个国家有关?", "俄罗斯", ("芬兰", "德国", "法国"), "绚濑绘里有俄罗斯血统,这也是角色设定里常被提到的点。", 4), - ("lovelive-maki-family", "缪斯学园偶像", "西木野真姬家的家庭背景最接近哪一种?", "医生家庭", ("神社家庭", "点心店家庭", "花店家庭"), "西木野真姬出身医生家庭。", 3), - ("lovelive-umi-role", "缪斯学园偶像", "园田海未在组合创作里经常负责哪一项?", "作词", ("编舞", "服装设计", "摄影"), "园田海未经常负责歌词创作。", 3), - ("lovelive-hanayo-rice", "缪斯学园偶像", "小泉花阳特别喜欢哪种食物?", "白米饭", ("鲷鱼烧", "番茄", "可乐饼"), "小泉花阳对白米饭有很强的热爱。", 2), - ("lovelive-nozomi-council", "缪斯学园偶像", "东条希在学生会里的职位是什么?", "副会长", ("会长", "书记", "风纪委员"), "东条希在学生会担任副会长。", 3), - ("minecraft-creeper-origin", "我的世界", "苦力怕最初的造型来源和哪种生物建模失误有关?", "猪", ("鸡", "牛", "羊"), "苦力怕的经典造型源自早期猪模型尺寸写错。", 5), - ("minecraft-repeater-delay", "我的世界", "红石中继器单个最多能设为几红石刻延迟?", "四红石刻", ("二红石刻", "六红石刻", "八红石刻"), "红石中继器单个最多四红石刻延迟。", 3), - ("minecraft-dragon-xp", "我的世界", "末影龙首次被击败时会掉落多少经验?", "一万二千", ("五千", "八千", "两万"), "末影龙首次死亡会掉落一万二千经验。", 4), - ("minecraft-netherite-ingot", "我的世界", "下界合金锭需要下界合金碎片再加哪种材料合成?", "金锭", ("铁锭", "钻石", "远古残骸"), "下界合金锭由下界合金碎片和金锭合成。", 3), - ("minecraft-shulker", "我的世界", "潜影贝主要自然生成在哪里?", "末地城", ("远古城市", "林地府邸", "海底神殿"), "潜影贝主要自然生成在末地城。", 3), - ("minecraft-wither-summon", "我的世界", "召唤凋灵需要摆放哪种头颅?", "凋灵骷髅头颅", ("骷髅头颅", "僵尸头颅", "龙首"), "召唤凋灵需要灵魂类方块和凋灵骷髅头颅。", 3), - ("minecraft-allay-vote", "我的世界", "悦灵是通过哪类官方活动胜出的生物?", "生物投票", ("愚人节快照", "节日活动", "地图竞赛"), "悦灵来自官方生物投票。", 4), - ("minecraft-warden-biome", "我的世界", "监守者机制主要关联哪个地下区域?", "深暗之域", ("繁茂洞穴", "滴水石洞穴", "下界荒地"), "监守者机制主要关联深暗之域和幽匿尖啸体。", 4), + ("cs-c4-timer", "反恐精英", "官方竞技规则里,炸弹安放后默认爆炸倒计时是多少秒?", "四十秒", ("三十五秒", "四十五秒", "五十秒"), "反恐精英竞技常规炸弹倒计时是四十秒,很多残局路线都按这个时间算。", 4), + ("cs-smoke-duration", "反恐精英", "反恐精英2 里烟雾弹完全展开后通常持续多久?", "十八秒", ("十五秒", "二十秒", "二十五秒"), "常规烟雾持续约十八秒,卡回防和爆弹节奏时很关键。", 4), + ("cs-fire-duration", "反恐精英", "燃烧弹或燃烧瓶火焰通常持续多久?", "七秒", ("五秒", "九秒", "十二秒"), "火焰持续约七秒,拖延拆包或清点都围绕这个窗口。", 4), + ("cs-mr12-premier", "反恐精英", "反恐精英2 优先模式(Premier)常规半场采用哪种回合制?", "单方最多十二回合", ("单方最多十五回合", "单方最多十回合", "单方最多八回合"), "优先模式常规为十二回合半场,和旧十五回合半场节奏不同。", 3), + ("cs-defuse-kit", "反恐精英", "带拆弹钳时,完整拆包时间会缩短到多少秒?", "五秒", ("四秒", "六秒", "七秒"), "无钳拆包十秒,有钳拆包五秒,残局听钳声和骗拆都靠这个数。", 3), + ("cs-loss-bonus", "反恐精英", "连续失败奖励在达到上限后,每名队员单回合基础失败奖励是多少?", "三千四百美元", ("二千九百美元", "三千美元", "三千七百美元"), "失败奖励阶梯最高为三千四百美元,是强起和经济局判断的关键数值。", 5), + ("apex-shield-cell-time", "顶点英雄", "使用小电池恢复护甲通常需要多久?", "三秒", ("二秒", "五秒", "八秒"), "小电池使用时间是三秒,和大电池五秒、医疗箱八秒节奏不同。", 3), + ("apex-phoenix-time", "顶点英雄", "凤凰治疗包完整使用时间是多少?", "十秒", ("八秒", "十二秒", "十五秒"), "凤凰治疗包同时回满血和甲,但需要十秒完整读条。", 4), + ("apex-grenade-stack", "顶点英雄", "当前背包里一个格子通常最多能放几颗手雷?", "一颗", ("两颗", "三颗", "四颗"), "手雷单格一颗会显著影响背包管理,这个改动让投掷物压制成本更高。", 4), + ("apex-wattson-accelerant", "顶点英雄", "哪位传奇使用终极技能加速剂时有特殊收益,能直接充满终极技能?", "华森", ("命脉", "班加罗尔", "瓦尔基里"), "华森的被动让终极技能加速剂直接充满终极技能。", 5), + ("apex-controller-console", "顶点英雄", "哪类传奇可以使用地图上的环形控制台读取下一圈信息?", "控制位", ("突击位", "游击位", "支援位"), "职业系统里控制位能读取下一圈信息,和侦察位扫描敌人信息不同。", 4), + ("apex-support-banner", "顶点英雄", "哪类传奇可以通过复制器制作队友旗帜?", "支援位", ("控制位", "突击位", "游击位"), "支援位能制作队友旗帜,这会改变残局复活路线。", 4), + ("overwatch-ramattra-pummel", "守望先锋", "拉玛刹进入天罚形态后,普通攻击拳波对屏障的关系更接近哪一种?", "可以穿过屏障打人", ("会被屏障完全挡住", "只能打屏障本体", "会治疗屏障后队友"), "天罚形态的拳波可以穿过屏障命中目标,是打盾后站位的关键细节。", 5), + ("overwatch-sigma-grasp", "守望先锋", "西格玛动能俘获不能吸收哪类伤害?", "光束类伤害", ("飞行弹道", "火箭弹", "榴弹"), "动能俘获吃弹道,不吃光束和近战类伤害。", 4), + ("overwatch-dva-matrix", "守望先锋", "D.Va 防御矩阵通常不能拦截哪类攻击?", "近战挥击", ("飞行弹丸", "部分终极弹道", "治疗弹道"), "防御矩阵主要吃弹道,近战、光束等类型不会被矩阵吞掉。", 4), + ("overwatch-ana-nade", "守望先锋", "安娜生物手雷命中敌人后,最核心的负面效果是什么?", "阻止其受到治疗", ("降低其移动速度", "禁用其换弹", "减少其弹药上限"), "生物手雷的禁疗效果能直接改变团战集火窗口。", 3), + ("overwatch-lucio-crossfade", "守望先锋", "卢西奥切歌的两个基础光环分别对应什么?", "治疗和加速", ("增伤和护盾", "隐身和侦测", "减伤和吸血"), "卢西奥核心循环就是治疗歌和加速歌的切换。", 2), + ("overwatch-mei-wall-cancel", "守望先锋", "小美冰墙放出后,玩家再次按技能键通常可以做什么?", "提前取消冰墙", ("让冰墙回血", "让冰墙移动", "把冰墙变成护盾"), "冰墙可以手动提前取消,很多封路和救人操作都靠这个细节。", 3), + ("lol-control-ward", "英雄联盟", "控制守卫通常不能直接显形哪类状态的英雄?", "真正隐形", ("伪装", "隐形陷阱", "普通守卫"), "控制守卫能看见伪装和陷阱,但不能直接让真正隐形单位显形。", 5), + ("lol-inhibitor-respawn", "英雄联盟", "召唤师峡谷水晶被摧毁后,通常多久后重生?", "五分钟", ("三分钟", "四分钟", "六分钟"), "水晶重生时间是五分钟,带线和远古资源交换经常围绕它计算。", 4), + ("lol-turret-plates", "英雄联盟", "防御塔镀层会在游戏时间什么时候脱落?", "十四分钟", ("十分钟", "十二分钟", "十五分钟"), "镀层十四分钟脱落,前期越塔和换线收益会受这个时间点影响。", 3), + ("lol-baron-spawn", "英雄联盟", "纳什男爵首次刷新时间是?", "二十分钟", ("十五分钟", "十八分钟", "二十五分钟"), "男爵二十分钟刷新,前一波视野和兵线准备通常会提前开始。", 2), + ("lol-yasuo-wall", "英雄联盟", "亚索风墙主要拦截哪类东西?", "飞行弹道", ("防御塔攻击", "持续光束", "地形效果"), "风墙挡飞行弹道,不是所有远程效果都会被挡。", 4), + ("lol-gangplank-orange", "英雄联盟", "普朗克橘子的核心功能除回血外还包括什么?", "解除控制", ("刷新火药桶", "获得隐身", "重置大招"), "坏血病疗法能解除控制,是船长对线和团战容错的重要细节。", 3), + ("gbp-fever", "少女乐团派对", "协力演出里,队伍表现达标后进入的全队加分段通常叫什么?", "狂热时间", ("安可时间", "挑战时间", "应援时间"), "协力演出里的狂热时间会影响整队得分,是多人房节奏点。", 4), + ("gbp-judgement-order", "少女乐团派对", "演奏判定从最好到较差,紧跟在完美之后的是哪一档?", "很好", ("好", "差", "失误"), "判定顺序里完美之后是很好,再往下才是好、差和失误。", 3), + ("gbp-live-boost", "少女乐团派对", "通常一次演出最多可以消耗多少个演出能量来提高奖励?", "三个", ("一个", "五个", "十个"), "演出能量影响奖励倍率,单次常规消耗上限是三个。", 4), + ("gbp-area-item", "少女乐团派对", "练习室、海报等区域道具主要影响什么?", "成员综合力", ("抽卡概率", "歌曲速度", "体力上限"), "区域道具会给乐队或属性提供加成,是配队总综合力的一部分。", 3), + ("gbp-challenge-live", "少女乐团派对", "挑战演出活动里,进入挑战曲通常要先消耗什么?", "挑战点数", ("星石", "好友点", "练习券"), "挑战演出需要先通过普通演出获取挑战点数,再打挑战曲。", 4), + ("gbp-special-chart", "少女乐团派对", "特殊难度谱面和专家谱面的关系更接近哪一种?", "另一张独立谱面", ("专家谱自动加速", "专家谱隐藏轨道", "专家谱减少判定"), "特殊难度通常是独立谱面,不只是把专家谱调快。", 4), + ("kpop-newjeans-attention", "韩流", "新牛仔(NewJeans)出道时最先空降公开的音乐录像是哪首?", "注意", ("炒作男孩", "饼干", "受伤"), "新牛仔(NewJeans)出道营销先公开《注意》的音乐录像,再连续展开其他内容。", 4), + ("kpop-redvelvet-concept", "韩流", "红贝贝(Red Velvet)的团体概念常被拆成哪两面?", "红与丝绒", ("月与太阳", "甜与苦", "黑与粉"), "红贝贝(Red Velvet)常用红与丝绒两面概念区分明亮和成熟风格。", 3), + ("kpop-music-show-encore", "韩流", "韩国打歌节目获一位后,现场常见的收尾舞台叫什么?", "安可舞台", ("预录舞台", "回归预告", "签售舞台"), "一位后的安可舞台经常被粉丝拿来观察现场唱功和团体互动。", 3), + ("kpop-lightstick-name", "韩流", "韩流粉丝应援棒在中文语境里通常被简称为什么?", "应援棒", ("打歌棒", "投票棒", "站位棒"), "应援棒是演唱会和打歌现场常见的视觉应援道具。", 2), + ("kpop-photocard", "韩流", "专辑小卡随机配置最直接影响粉丝哪种行为?", "拆专收卡", ("直播投票", "现场排队", "舞台换位"), "随机小卡会驱动拆专、交换和收集,是韩流专辑消费的重要机制。", 4), + ("kpop-fanchant", "韩流", "打歌舞台里粉丝按固定词句一起喊的应援内容通常叫?", "应援词", ("站位表", "预告词", "抽选词"), "应援词会配合歌曲段落出现,是现场文化的一部分。", 3), + ("genshin-superconduct", "原神", "超导反应最核心的战斗收益是什么?", "降低物理抗性", ("降低水元素抗性", "生成护盾", "恢复元素能量"), "超导会降低敌人物理抗性,主要服务物理伤害打法。", 4), + ("genshin-dendro-core-limit", "原神", "场上草原核数量超过上限时,通常会怎样?", "较早生成的草原核会提前爆炸", ("所有草原核消失", "刷新持续时间", "变成晶片"), "草原核有场上数量限制,超过后旧核会提前触发爆炸。", 5), + ("genshin-hyperbloom", "原神", "超绽放由什么元素触发草原核产生?", "雷元素", ("火元素", "冰元素", "风元素"), "雷元素命中草原核会触发超绽放,生成追踪性质的伤害。", 3), + ("genshin-burgeon", "原神", "烈绽放由什么元素触发草原核产生?", "火元素", ("雷元素", "岩元素", "冰元素"), "火元素命中草原核会触发烈绽放,造成范围草元素伤害。", 3), + ("genshin-crystallize", "原神", "结晶反应掉落的晶片主要提供什么?", "对应元素护盾", ("元素能量", "暴击率加成", "治疗效果"), "岩元素和可结晶元素反应会产生晶片,拾取后形成对应元素护盾。", 3), + ("genshin-resin-cap", "原神", "当前原粹树脂自然恢复上限是多少?", "二百", ("一百六十", "一百八十", "二百四十"), "原粹树脂上限后来提高到二百,日常体力规划随之变化。", 4), + ("lovelive-snow-halation", "缪斯学园偶像", "《雪色光晕》演出中,观众应援色由白转橙通常对应谁的独唱段?", "高坂穗乃果", ("南小鸟", "园田海未", "绚濑绘里"), "白转橙是《雪色光晕》现场文化中非常有名的段落。", 4), + ("lovelive-token-event", "缪斯学园偶像", "学园偶像祭传统代币活动里,打活动曲通常要消耗什么?", "活动道具", ("友情点", "练习贴纸", "社员证"), "代币活动先刷普通歌曲拿活动道具,再消耗道具打活动曲。", 4), + ("lovelive-score-match", "缪斯学园偶像", "学园偶像祭的分数赛活动核心更接近哪种玩法?", "多人按分数排名", ("单人剧情解谜", "抽卡保底挑战", "社团领地战"), "分数赛会把玩家匹配到一起,按歌曲得分排位结算。", 4), + ("lovelive-medley", "缪斯学园偶像", "学园偶像祭的串烧嘉年华一次最多连续打几首歌?", "三首", ("两首", "四首", "五首"), "串烧嘉年华可以选择连续打一到三首歌,体力和稳定性都更吃紧。", 4), + ("lovelive-bibi", "缪斯学园偶像", "小队碧碧(BiBi)由哪组成员组成?", "绘里、真姬、妮可", ("穗乃果、小鸟、花阳", "海未、凛、希", "小鸟、海未、绘里"), "碧碧(BiBi)成员是绚濑绘里、西木野真姬、矢泽妮可。", 3), + ("lovelive-printemps", "缪斯学园偶像", "小队春色少女(Printemps)由哪组成员组成?", "穗乃果、小鸟、花阳", ("绘里、真姬、妮可", "海未、凛、希", "穗乃果、凛、妮可"), "春色少女(Printemps)成员是高坂穗乃果、南小鸟、小泉花阳。", 3), + ("minecraft-beacon-base", "我的世界", "满级信标金字塔如果全部铺满,一共需要多少个方块?", "一百六十四个", ("一百二十八个", "一百四十四个", "一百九十二个"), "满级信标底座为九乘九、七乘七、五乘五、三乘三,合计一百六十四个方块。", 5), + ("minecraft-bookshelves", "我的世界", "附魔台达到三十级附魔通常最多需要多少个书架参与加成?", "十五个", ("十二个", "十八个", "二十个"), "十五个有效书架即可提供三十级附魔所需的书架加成。", 3), + ("minecraft-nether-portal-min", "我的世界", "不算四个角,最小下界传送门框架需要多少个黑曜石?", "十个", ("八个", "十二个", "十四个"), "最小传送门外框是四乘五,四角可省,所以最少十个黑曜石。", 4), + ("minecraft-respawn-anchor", "我的世界", "重生锚在哪个维度用于设定重生点?", "下界", ("主世界", "末地", "深暗之域"), "重生锚用于下界重生,在主世界或末地使用会爆炸。", 4), + ("minecraft-comparator-composter", "我的世界", "堆肥桶满级时,比较器读取到的红石信号强度是多少?", "八", ("七", "九", "十五"), "堆肥桶从空到满对应零到八级比较器信号。", 5), + ("minecraft-sponge-nether", "我的世界", "湿海绵放在下界时会发生什么?", "立刻变干", ("变成岩浆", "掉落成物品", "无法放置"), "湿海绵在下界会立即干燥,这是处理湿海绵的冷门方法。", 4), ) TRIVIA_TEMPLATES = ( "【{domain} 冷知识】{prompt}", @@ -919,9 +856,9 @@ def split_chat_reply_line(line: str) -> list[str]: def style_chat_reply_text(value: object) -> str: raw_lines = [ - normalize_text(line) + normalize_text(CHAT_REPLY_TRIVIA_HINT.sub("", line)) for line in str(value or "").splitlines() - if normalize_text(line) + if normalize_text(CHAT_REPLY_TRIVIA_HINT.sub("", line)) ] if not raw_lines: return "" diff --git a/packages/jwebot-official-extensions/pyproject.toml b/packages/jwebot-official-extensions/pyproject.toml index f8e6bed..b936f17 100644 --- a/packages/jwebot-official-extensions/pyproject.toml +++ b/packages/jwebot-official-extensions/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "jwebot-official-extensions" -version = "1.2.7b1+1019" +version = "1.2.8b1+1019" description = "Reviewed local command adapters and broker implementation for JWeBot" requires-python = ">=3.9" dependencies = [ - "jwebot-sdk==1.2.7b1+1019", + "jwebot-sdk==1.2.8b1+1019", ] [tool.setuptools.packages.find] diff --git a/packages/jwebot-official-extensions/src/jwebot_official_extensions/__init__.py b/packages/jwebot-official-extensions/src/jwebot_official_extensions/__init__.py index 5134a0b..f6c3fcc 100644 --- a/packages/jwebot-official-extensions/src/jwebot_official_extensions/__init__.py +++ b/packages/jwebot-official-extensions/src/jwebot_official_extensions/__init__.py @@ -90,4 +90,4 @@ __all__ = [ "render_feature_list", ] -__version__ = "1.2.7b1+1019" +__version__ = "1.2.8b1+1019" diff --git a/packages/jwebot-sdk/pyproject.toml b/packages/jwebot-sdk/pyproject.toml index 72a9fec..121c06b 100644 --- a/packages/jwebot-sdk/pyproject.toml +++ b/packages/jwebot-sdk/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "jwebot-sdk" -version = "1.2.7b1+1019" +version = "1.2.8b1+1019" description = "Typed, capability-limited extension API for JWeBot plugins" requires-python = ">=3.9" dependencies = [] diff --git a/packages/jwebot-sdk/src/jwebot_sdk/__init__.py b/packages/jwebot-sdk/src/jwebot_sdk/__init__.py index 1460c3c..f606241 100644 --- a/packages/jwebot-sdk/src/jwebot_sdk/__init__.py +++ b/packages/jwebot-sdk/src/jwebot_sdk/__init__.py @@ -38,4 +38,4 @@ __all__ = [ "SingleGroupContext", ] -__version__ = "1.2.7b1+1019" +__version__ = "1.2.8b1+1019" diff --git a/pyproject.toml b/pyproject.toml index beab4cb..cc3f286 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.jwebot] -release = "beta 1.2.7.1019" +release = "beta 1.2.8.1019" production_deployments_enabled_by_default = false [tool.jwebot.workspace] diff --git a/tests/test_jwebot_edge.py b/tests/test_jwebot_edge.py index 0dc500a..c75ebbd 100644 --- a/tests/test_jwebot_edge.py +++ b/tests/test_jwebot_edge.py @@ -236,6 +236,10 @@ class RoutingTests(unittest.TestCase): MODULE.clean_chat_reply("作为AI我无法比较。\n李神是谁?"), "李神是谁喵", ) + self.assertEqual( + MODULE.clean_chat_reply("你说“一切”是啥意思喵?做题就 /回答 A喵"), + "你说“一切”是啥意思喵", + ) self.assertEqual( MODULE.unpack_reply_parts(MODULE.clean_chat_reply( "这波像是脑子知道要撤,但是手完全没同意," @@ -1035,9 +1039,9 @@ class LedgerAndApplicationTests(unittest.TestCase): self.assertEqual(version["route"], "local") self.assertIn("JWeBot 版本", version["text"]) self.assertIn("kernel", version["text"]) - self.assertIn("最新版本:beta 1.2.7.1019", version["text"]) - self.assertIn("更新时间:2026-10-19 22:37:40", version["text"]) - self.assertIn("更新摘要:冷门知识问答新增缪斯学园偶像和我的世界题库", version["text"]) + self.assertIn("最新版本:beta 1.2.8.1019", version["text"]) + self.assertIn("更新时间:2026-10-19 22:49:30", version["text"]) + self.assertIn("更新摘要:冷门知识问答题库整体重写", version["text"]) self.assertEqual(debug["route"], "local") self.assertIn("调试埋点", debug["text"]) self.assertEqual(balance["route"], "local") @@ -1330,8 +1334,10 @@ class LedgerAndApplicationTests(unittest.TestCase): ) for question in bank ) - self.assertFalse(any("A" <= character <= "Z" for character in display_text)) - self.assertFalse(any("a" <= character <= "z" for character in display_text)) + self.assertIn("新牛仔(NewJeans)", display_text) + self.assertIn("碧碧(BiBi)", display_text) + self.assertNotIn("地平线一直想回去见到的儿子", display_text) + self.assertNotIn("蒙德风神的真实魔神名", display_text) topics = {str(question["topic"]) for question in bank} self.assertIn("缪斯学园偶像", topics) self.assertIn("我的世界", topics) diff --git a/tests/test_release_update.py b/tests/test_release_update.py index c8a3cda..a88e565 100644 --- a/tests/test_release_update.py +++ b/tests/test_release_update.py @@ -20,7 +20,7 @@ SPEC.loader.exec_module(MODULE) class ReleaseUpdateTests(unittest.TestCase): - release = "beta 1.2.7.1019" + release = "beta 1.2.8.1019" def setUp(self): self.temporary = tempfile.TemporaryDirectory()