新增运势系统

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", "plugin_dir": "Plugins",
"host": "0.0.0.0", "host": "0.0.0.0",
"port": 8000, "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.Convention.Runtime.Config import *
from PWF.CoreModules.plugin_interface import PluginInterface from PWF.CoreModules.plugin_interface import PluginInterface
from PWF.CoreModules.flags import * from PWF.CoreModules.flags import *
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ProjectConfig from PWF.Convention.Runtime.GlobalConfig import ProjectConfig
from PWF.Convention.Runtime.Web import ToolURL from PWF.Convention.Runtime.Web import ToolURL
from PWF.Convention.Runtime.String import LimitStringLength from PWF.Convention.Runtime.String import LimitStringLength
import httpx import httpx
import re import re
logger = ProjectConfig() logger: ProjectConfig = Architecture.Get(ProjectConfig)
MAIN_WEBHOOK_URL = logger.FindItem("main_webhook_url", "") MAIN_WEBHOOK_URL = logger.FindItem("main_webhook_url", "")
logger.SaveProperties() 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"]