优化定时订阅内容

This commit is contained in:
liuwei
2025-12-17 13:56:52 +08:00
parent 5ed8f48afc
commit 4bf44a5592

View File

@@ -13,6 +13,7 @@ from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
from wechat_ipad import WechatAPIClient
from utils.decorator.async_job import async_job
# ================= Redis 管理器 =================
@@ -113,8 +114,9 @@ class WeatherPlugin(MessagePluginInterface):
self.feature = self.register_feature()
self.redis_manager = None
self._config = {}
self.bot_client = None
self.task = None
# 使用统一的异步定时任务系统,避免手写休眠循环
async_job.at_times(["08:00"])(self._execute_daily_push)
self.bot: WechatAPIClient = None
def initialize(self, context: Dict[str, Any]) -> bool:
"""初始化"""
@@ -136,14 +138,11 @@ class WeatherPlugin(MessagePluginInterface):
def start(self) -> bool:
self.LOG.info(f"[{self.name}] 插件已启动")
self.status = PluginStatus.RUNNING
self.task = asyncio.create_task(self._daily_scheduler())
return True
def stop(self) -> bool:
self.LOG.info(f"[{self.name}] 插件已停止")
self.status = PluginStatus.STOPPED
if self.task:
self.task.cancel()
return True
def can_process(self, message: Dict[str, Any]) -> bool:
@@ -160,9 +159,7 @@ class WeatherPlugin(MessagePluginInterface):
sender = message.get("sender")
roomid = message.get("roomid", "")
gbm: GroupBotManager = message.get("gbm")
bot: WechatAPIClient = message.get("bot")
if not self.bot_client: self.bot_client = bot
self.bot: WechatAPIClient = message.get("bot")
if roomid and gbm.get_group_permission(roomid, self.feature) == PermissionStatus.DISABLED:
return False, "没有权限"
@@ -202,7 +199,7 @@ class WeatherPlugin(MessagePluginInterface):
# 反馈时告诉用户标准名
msg = f"✅ 订阅成功!\n已锁定城市:{city_info['adm1']} - {std_city_name}\n每天 08:00 推送早报。"
await bot.send_text_message(roomid or sender, msg, sender)
await self.bot.send_text_message(roomid or sender, msg, sender)
# Step C: 顺便存历史 (用于明天对比)
# 使用 ID 获取天气,避免再次 Geo 查询
@@ -217,7 +214,7 @@ class WeatherPlugin(MessagePluginInterface):
if not self.redis_manager: return False, "数据库不可用"
unique_id = f"{roomid}_{sender}" if roomid else f"private_{sender}"
self.redis_manager.remove_subscription(unique_id)
await bot.send_text_message(roomid or sender, "✅ 已取消天气订阅。", sender)
await self.bot.send_text_message(roomid or sender, "✅ 已取消天气订阅。", sender)
return True, "取消成功"
# 3. 普通查询 (保持原逻辑,但也建议先 lookup 再查,或者复用 lookup)
@@ -230,35 +227,12 @@ class WeatherPlugin(MessagePluginInterface):
weather_text = await self._get_weather_text_response(input_city)
if not weather_text: return False, "查询失败"
await bot.send_text_message(roomid or sender, weather_text, sender)
await self.bot.send_text_message(roomid or sender, weather_text, sender)
return True, "发送成功"
# ================= 定时任务系统 =================
async def _daily_scheduler(self):
"""每日 08:00 调度器"""
self.LOG.info("⏰ 天气订阅定时任务已启动...")
while self.status == PluginStatus.RUNNING:
try:
now = datetime.datetime.now()
target_time = now.replace(hour=8, minute=0, second=0, microsecond=0)
if now > target_time:
target_time += datetime.timedelta(days=1)
wait_seconds = (target_time - now).total_seconds()
self.LOG.info(f"⏳ 下一次天气推送将在 {wait_seconds:.0f} 秒后")
await asyncio.sleep(wait_seconds)
if self.bot_client and self.redis_manager:
await self._execute_daily_push()
await asyncio.sleep(60)
except asyncio.CancelledError:
break
except Exception as e:
self.LOG.error(f"定时任务异常: {e}")
await asyncio.sleep(60)
async def _execute_daily_push(self):
"""执行全量推送 (基于 ID 聚合)"""
@@ -305,9 +279,9 @@ class WeatherPlugin(MessagePluginInterface):
await asyncio.sleep(0.5)
try:
if self.bot_client:
await self.bot_client.send_text_message(target_id, final_msg,
sender_id if room_id else None)
if self.bot:
await self.bot.send_at_message(target_id, final_msg,
[sender_id])
except Exception as send_e:
self.LOG.error(f"推送给 {target_id} 失败: {send_e}")
@@ -340,7 +314,7 @@ class WeatherPlugin(MessagePluginInterface):
if life_tips: msg += "\n💡 **温馨提示**\n" + "\n".join(life_tips) + "\n"
msg += f"\n👔 **穿衣**{clothing}"
# 增加一些趣味数据
msg += self._get_fun_stats(today)
@@ -378,7 +352,7 @@ class WeatherPlugin(MessagePluginInterface):
alerts.append("❄️ **冰雪天气**:路面湿滑,注意行车安全。")
elif "冰雹" in text_day:
alerts.append("☄️ **冰雹警报**:赶紧把车停到室内!")
# 4. 风力
try:
# windScaleDay 可能是 "1-2" 或 "3"
@@ -390,12 +364,12 @@ class WeatherPlugin(MessagePluginInterface):
alerts.append(f"🌬️ **大风警报**{wind_dir}{wind_scale}级,发型要乱啦。")
except:
pass
return alerts
def _generate_life_tips(self, data: dict) -> List[str]:
tips = []
# 1. 降水 (precip)
precip = float(data.get('precip', 0.0))
text_day = data.get('textDay', '')
@@ -415,14 +389,14 @@ class WeatherPlugin(MessagePluginInterface):
tips.append("☠️ **紫外线爆表**:尽量留在室内,出门必须全副武装!")
elif uv >= 6:
tips.append("☂️ **紫外线强**:涂好防晒霜,戴上墨镜。")
# 3. 湿度 (humidity)
hum = int(data.get('humidity', 0))
if hum >= 90:
tips.append("💧 空气像是能拧出水(湿度>90%),注意防潮除湿。")
elif hum <= 20:
tips.append("🌵 空气很干燥(湿度<20%),多喝水,小心静电。")
# 4. 气压 (pressure)
pres = int(data.get('pressure', 1000))
if pres < 995:
@@ -440,7 +414,7 @@ class WeatherPlugin(MessagePluginInterface):
sunset = data.get('sunset', '')
if cloud < 20 and "" in text_day:
tips.append(f"<EFBFBD> 傍晚{sunset}左右可能有美丽的晚霞哦。")
return tips
def _get_fun_stats(self, data: dict) -> str:
@@ -448,10 +422,10 @@ class WeatherPlugin(MessagePluginInterface):
sunrise = data.get('sunrise', '-')
sunset = data.get('sunset', '-')
moon_phase = data.get('moonPhase', '')
moon_icon = data.get('moonPhaseIcon', '') # 假设API有这个或者直接用 phase
moon_icon = data.get('moonPhaseIcon', '') # 假设API有这个或者直接用 phase
stats = []
# 计算白昼时长
try:
sr_h, sr_m = map(int, sunrise.split(':'))
@@ -471,14 +445,14 @@ class WeatherPlugin(MessagePluginInterface):
def _get_clothing_advice(self, t_min: int, t_max: int) -> str:
"""根据最低和最高温综合给出穿衣建议"""
avg_temp = (t_min + t_max) / 2
if t_min < -5:
return "极寒!羽绒服+保暖内衣+围巾手套缺一不可。"
elif t_min < 5:
return "很冷,建议穿棉衣、羽绒服,里面穿毛衣。"
elif t_min < 12:
return "较冷,大衣或厚外套是标配。"
if avg_temp < 18:
return "凉爽,建议风衣、卫衣或薄外套,早晚保暖。"
elif avg_temp < 24:
@@ -547,7 +521,7 @@ class WeatherPlugin(MessagePluginInterface):
data = today_fc.copy()
# 补充 date 字段,方便后续处理
data["date"] = datetime.datetime.now().strftime("%Y-%m-%d")
self.redis_manager.save_history(city_id, data)
except Exception as e:
self.LOG.error(f"存档失败: {e}")