Add HeXi bot codebase: custom plugins, web frontends, tests

- hexi core: message handling, rate limiting, cooldown, plugin manager
- Custom plugins: BF stats, daily check-in, quotes, persona cards, etc.
- Community plugins vendored under hexi/plugins with local fixes
- Web admin frontends (learning-chat, persona-admin), unified hexi/web
- Tests for rate_limit/cooldown/memes/persona; poetry.lock

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-01 13:13:40 +08:00
co-authored by Claude
parent 1783c60afa
commit b61d09f09f
3201 changed files with 160436 additions and 171 deletions
@@ -0,0 +1,151 @@
import json
import random
import json
import random
import asyncio
import os
from typing import List
from nonebot.adapters.onebot.v11 import MessageSegment, PokeNotifyEvent, Message
from nonebot.plugin.on import on_notice, on_command
from nonebot import on_type, on_message, logger
from nonebot.adapters import Event
from nonebot.matcher import Matcher
from nonebot.params import CommandArg
from nonebot.rule import to_me
from nonebot_plugin_alconna import UniMessage, get_target
from nonebot.plugin import PluginMetadata
from hexi.plugins.nonebot_plugin_hexi_core.message_utils import send_poke
__plugin_meta__ = PluginMetadata(
name="随机JM码",
description="随机发送JM码,支持添加与屏蔽",
usage="@bot 触发随机JM码;jm 添加JM码",
type="application",
)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
FILE_PATH = os.path.join(BASE_DIR, "jm_code.json")
TEXT_TEMPLATES = [
"给你{code},拿去吧",
"给你{code},记得谢谢我",
"给你{code},注意保养弹簧"
]
BLOCK_CODE = ["350235", "350234"]
WHITE_LIST = ["1019165018"]
jm_handler = on_notice(priority=10, block=False, rule=to_me())
add_jm_code = on_command("jm", rule=to_me())
@add_jm_code.handle()
async def add_more_jm_code(event: Event, matcher: Matcher):
input_code = event.get_message().extract_plain_text().strip()
cmd = matcher.state["_prefix"]["command"][0]
input_code = input_code.replace(cmd, "")
if input_code in BLOCK_CODE:
await UniMessage.at(event.get_user_id()).text(" 不准发石!!").send()
return
await add_new_jm_code(input_code)
await UniMessage.reply(event.get_user_id()).text(" 添加成功").send()
return
@jm_handler.handle()
async def random_jm_code(event: Event, poke_event: PokeNotifyEvent):
user_id = event.get_user_id()
logger.info(f"{user_id}触发了戳一戳")
target = get_target(event)
group_id = target.parent_id or target.id or poke_event.group_id
logger.info(f"触发戳一戳的群聊:{group_id}")
if group_id in WHITE_LIST:
logger.info(f"白名单:{group_id}")
choice = random.randint(0, 100)
logger.info(f"触发概率:{choice}")
if choice >= 50:
await poke_reply(event)
else:
logger.info("不做操作")
else:
logger.info(f"不在白名单:{group_id}")
if target.private:
group_id = None
result = await send_poke(group_id=group_id, user_id=user_id)
logger.info(result)
return
async def poke_reply(event: Event):
user_id = event.get_user_id()
jm_message = await get_random_jm_code()
await UniMessage.at(user_id).text(" " + jm_message).send()
JM_CODES: List[int] = []
_LOADED = False
LOCK = asyncio.Lock()
def _safe_write_json(data, file_path: str):
tmp_path = file_path + ".tmp"
with open(tmp_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 原子替换(防止写一半崩溃)
os.replace(tmp_path, file_path)
async def load_codes(file_path: str = FILE_PATH):
global JM_CODES, _LOADED
if _LOADED:
return
async with LOCK:
if _LOADED:
return
if not os.path.exists(file_path):
JM_CODES = []
_safe_write_json(JM_CODES, file_path)
else:
with open(file_path, "r", encoding="utf-8") as f:
try:
JM_CODES = json.load(f)
except json.JSONDecodeError:
# 文件损坏时兜底
JM_CODES = []
_LOADED = True
async def get_random_jm_code() -> str:
await load_codes()
if not JM_CODES:
return "暂无可用代码"
code = random.choice(JM_CODES)
logger.info(f"随机JM:{code}")
template = random.choice(TEXT_TEMPLATES)
return template.format(code=code)
async def add_new_jm_code(new_code: int) -> bool:
await load_codes()
async with LOCK:
if new_code in JM_CODES:
return False # 已存在
JM_CODES.append(new_code)
_safe_write_json(JM_CODES, FILE_PATH)
return True
@@ -0,0 +1,286 @@
[
"219",
"224",
"759",
"877",
"878",
"2057",
"2388",
"2868",
"4333",
"6102",
"6411",
"18212",
"20106",
"20348",
"20902",
"21274",
"21407",
"21994",
"22392",
"27512",
"27701",
"28650",
"33775",
"39509",
"46555",
"47729",
"50514",
"54747",
"55427",
"58267",
"61257",
"62268",
"69354",
"73451",
"74891",
"77778",
"78665",
"80358",
"85055",
"86779",
"89218",
"98509",
"98669",
"101792",
"104738",
"105854",
"107184",
"114445",
"116157",
"122333",
"122427",
"124116",
"124561",
"125237",
"127282",
"135697",
"138809",
"140620",
"142464",
"142568",
"145289",
"148486",
"148624",
"149578",
"149906",
"151607",
"151696",
"181107",
"181611",
"190447",
"192957",
"203446",
"207063",
"209232",
"218796",
"220455",
"220995",
"220996",
"221659",
"223153",
"224879",
"225764",
"230702",
"230806",
"231692",
"235366",
"239642",
"239797",
"241726",
"245189",
"247044",
"248646",
"249121",
"251050",
"255015",
"258778",
"263104",
"265236",
"266615",
"268453",
"269417",
"271249",
"273943",
"278032",
"281142",
"284185",
"285994",
"290391",
"291407",
"293593",
"293867",
"303683",
"305291",
"305428",
"306326",
"306848",
"308472",
"308595",
"310176",
"318730",
"318731",
"322028",
"326357",
"329995",
"333722",
"334554",
"343898",
"346346",
"346862",
"352727",
"355019",
"355659",
"362197",
"362460",
"368639",
"368837",
"369504",
"370634",
"371570",
"371631",
"371875",
"373099",
"374495",
"377532",
"380052",
"382336",
"384297",
"385372",
"389479",
"390353",
"392326",
"394523",
"395280",
"395281",
"397150",
"397478",
"398569",
"401496",
"401574",
"409658",
"409896",
"410841",
"411613",
"412004",
"415513",
"417463",
"427706",
"429322",
"433023",
"434797",
"434801",
"435777",
"441189",
"441594",
"442137",
"443170",
"445794",
"448098",
"451603",
"451610",
"452501",
"452699",
"453931",
"454803",
"465335",
"467110",
"467180",
"468624",
"469738",
"471872",
"472952",
"475378",
"476677",
"477029",
"477990",
"478437",
"479907",
"480142",
"480841",
"481536",
"481979",
"482542",
"484683",
"485647",
"485870",
"486253",
"487798",
"488125",
"495051",
"495256",
"498750",
"501638",
"501838",
"502132",
"505048",
"505241",
"505253",
"505484",
"507975",
"508253",
"509489",
"509834",
"511010",
"513984",
"515569",
"517500",
"523276",
"524360",
"527354",
"529468",
"533458",
"533552",
"537119",
"541285",
"541762",
"542252",
"543247",
"543525",
"543749",
"544360",
"544401",
"545733",
"547590",
"549168",
"550176",
"552312",
"554413",
"563746",
"608258",
"1020570",
"1060990",
"1071423",
"1176067",
"1190464",
"1193587",
"1196804",
"1202415",
"1206636",
"1212262",
"1212643",
"1215962",
"1216628",
"1217450",
"1222299",
"1222320",
"1222393",
"1223363",
"1224091",
"1224493",
"2904551",
"3037141",
"3157283",
"3300062",
"3481682",
"3918941",
"3921012",
"4214502",
"4283473",
"4283484",
"4366352",
"4380002",
"5430811",
"1434077",
"1423811"
]