新增运势系统

This commit is contained in:
2025-11-08 14:10:08 +08:00
parent fb74fe0f34
commit 4129122016
5 changed files with 157 additions and 3 deletions

View File

@@ -0,0 +1,34 @@
# 背景
文件名2025-11-08_2_fortune-system.md
创建于2025-11-08_13:42:44
创建者liubai095\\asus
主分支main
任务分支:未创建
Yolo模式Off
# 任务描述
`Plugins/WPSFortuneSystem.py` 中开发一个与运气相关的系统,提供一个无参数指令“运势”,输出 -1 与 1 之间的数值及对应阶段文本,该数值基于当前小时与 `user_id` 哈希计算后乘以系数以保持稳定。将该数值计算封装为可复用接口,供其他允许被运气影响的系统调用,以影响结果。
# 项目概览
新WPS Bot 插件系统,包含核心模块与多种插件,需与现有插件接口保持兼容。
# 分析
当前插件体系通过 `PluginInterface.execute` 将实例注册到 `Architecture`,并在回调路由中按首个指令词定位插件;`WPSAPI``BasicWPSInterface` 已封装 webhook 回复、@ 解析等能力,提供统一的 Markdown 推送流程。运势插件继承该体系即可获得命令入口,并允许其他模块通过 `Architecture.Get(WPSFortuneSystem)` 访问其接口。
# 提议的解决方案
方案A`WPSFortuneSystem` 内实现 `FortuneCalculator`,以 `datetime.now().hour``user_id` 组合后的哈希映射到 (-1, 1),再借助细粒度阈值表输出阶段文本;对外暴露 `get_fortune_info(user_id, dt=None)`,同时注册 `运势`/`fortune` 指令返回 Markdown。
方案B将哈希映射与阶段判定抽离到 `Plugins/utils/fortune_service.py` 等独立模块,插件只负责命令交互;其他系统可直接导入服务或通过 `Architecture` 获取实例,需留意插件加载顺序与依赖。
# 当前执行步骤:"3. 分析任务相关代码"
# 任务进度
2025-11-08_14:01:11
- 已修改Plugins/WPSFortuneSystem.py
- 更改:实现整点哈希运势计算、阶段判定与指令回调
- 原因:提供可复用的运势接口与“运势”指令
- 阻碍因素:无
- 状态:成功
# 最终审查
- 代码审查:实现与计划一致,运势计算、阶段判定及接口公开范围均符合预期。
- 测试情况:通过。

View File

@@ -15,6 +15,8 @@
"plugin_dir": "Plugins",
"host": "0.0.0.0",
"port": 8000,
"verbose": false
"verbose": false,
"scheduler_tick_ms": 60000,
"scheduler_max_batch": 1000
}
}

2
PWF

Submodule PWF updated: b5fe23342d...16ef75c3ce

View File

@@ -1,13 +1,14 @@
from PWF.Convention.Runtime.Config import *
from PWF.CoreModules.plugin_interface import PluginInterface
from PWF.CoreModules.flags import *
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ProjectConfig
from PWF.Convention.Runtime.Web import ToolURL
from PWF.Convention.Runtime.String import LimitStringLength
import httpx
import re
logger = ProjectConfig()
logger: ProjectConfig = Architecture.Get(ProjectConfig)
MAIN_WEBHOOK_URL = logger.FindItem("main_webhook_url", "")
logger.SaveProperties()

117
Plugins/WPSFortuneSystem.py Normal file
View File

@@ -0,0 +1,117 @@
from __future__ import annotations
import hashlib
from datetime import datetime
from functools import lru_cache
from typing import Any, Dict, List, Tuple, Type, override
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
from .WPSAPI import WPSAPI
logger: ProjectConfig = Architecture.Get(ProjectConfig)
_HASH_BYTES = 16
_HASH_MAX = (1 << (_HASH_BYTES * 8)) - 1
_FORTUNE_STAGE_TABLE: List[Tuple[float, str]] = [
(-0.9, "厄运深谷"),
(-0.7, "凶多吉少"),
(-0.5, "多有波折"),
(-0.3, "略显低迷"),
(-0.1, "风平浪静"),
(0.1, "小有起色"),
(0.3, "渐入佳境"),
(0.5, "好运上扬"),
(0.7, "顺风顺水"),
(0.9, "鸿运当头"),
(1.01, "天命所归"),
]
class WPSFortuneSystem(WPSAPI):
"""基于整点哈希的运势系统,可供其他模块复用"""
@override
def dependencies(self) -> List[Type]:
return [WPSAPI]
@override
def is_enable_plugin(self) -> bool:
return True
@override
def wake_up(self) -> None:
logger.Log("Info", f"{ConsoleFrontColor.GREEN}WPSFortuneSystem 插件已加载{ConsoleFrontColor.RESET}")
self.register_plugin("运势")
self.register_plugin("fortune")
@override
async def callback(self, message: str, chat_id: int, user_id: int) -> str | None:
fortune_message = self._format_fortune_message(user_id)
return await self.send_markdown_message(fortune_message, chat_id, user_id)
def get_fortune_value(self, user_id: int, dt: datetime | None = None) -> float:
hour_dt, hour_key = self._resolve_hour(dt)
return self._compute_fortune_value(user_id, hour_key)
def get_fortune_stage(self, user_id: int, dt: datetime | None = None) -> str:
value = self.get_fortune_value(user_id, dt)
return self._match_stage(value)
def get_fortune_info(self, user_id: int, dt: datetime | None = None) -> Dict[str, Any]:
hour_dt, hour_key = self._resolve_hour(dt)
value = self._compute_fortune_value(user_id, hour_key)
stage = self._match_stage(value)
return {
"value": value,
"stage": stage,
"hour_key": hour_key,
"hour_label": hour_dt.strftime("%Y-%m-%d %H:00"),
"timestamp": hour_dt.isoformat(),
}
def _resolve_hour(self, dt: datetime | None) -> Tuple[datetime, str]:
target_dt = dt or datetime.now()
hour_dt = target_dt.replace(minute=0, second=0, microsecond=0)
return hour_dt, hour_dt.isoformat()
def _format_fortune_message(self, user_id: int) -> str:
info = self.get_fortune_info(user_id)
value_display = f"{info['value']:.4f}"
return (
"# 🎲 运势占卜\n"
f"- 运势值:`{value_display}`\n"
f"- 运势阶段:{info['stage']}\n"
f"- 基准整点:{info['hour_label']}\n"
"> 运势每整点刷新,允许运气加成的系统会复用同一结果。"
)
def _match_stage(self, value: float) -> str:
for upper_bound, label in _FORTUNE_STAGE_TABLE:
if value < upper_bound:
return label
return _FORTUNE_STAGE_TABLE[-1][1]
@staticmethod
@lru_cache(maxsize=2048)
def _cached_hash_value(user_id: int, hour_key: str) -> float:
payload = f"{user_id}:{hour_key}".encode("utf-8")
digest = hashlib.sha256(payload).digest()[:_HASH_BYTES]
integer = int.from_bytes(digest, "big")
normalized = integer / _HASH_MAX if _HASH_MAX else 0.0
mapped = normalized * 2 - 1
return max(-0.9999, min(0.9999, mapped))
def _compute_fortune_value(self, user_id: int, hour_key: str) -> float:
try:
return self._cached_hash_value(user_id, hour_key)
except Exception as exc:
logger.Log(
"Warning",
f"{ConsoleFrontColor.YELLOW}计算运势时出现异常: {exc}{ConsoleFrontColor.RESET}",
)
return 0.0
__all__ = ["WPSFortuneSystem"]