天气订阅功能优化
This commit is contained in:
@@ -21,25 +21,25 @@ class WeatherRedisManager:
|
|||||||
"""处理 Redis 数据存取"""
|
"""处理 Redis 数据存取"""
|
||||||
|
|
||||||
def __init__(self, db_manager):
|
def __init__(self, db_manager):
|
||||||
self.redis = db_manager
|
self.redis = db_manager.get_redis_connection()
|
||||||
self.prefix = "bot:weather:"
|
self.prefix = "bot:weather:"
|
||||||
|
|
||||||
async def add_subscription(self, key: str, data: dict):
|
def add_subscription(self, key: str, data: dict):
|
||||||
"""添加订阅 (存入标准城市名和ID)"""
|
"""添加订阅 (存入标准城市名和ID)"""
|
||||||
redis_key = f"{self.prefix}subs"
|
redis_key = f"{self.prefix}subs"
|
||||||
# 存入 JSON 字符串
|
# 存入 JSON 字符串
|
||||||
await self.redis.hset(redis_key, key, json.dumps(data, ensure_ascii=False))
|
self.redis.hset(redis_key, key, json.dumps(data, ensure_ascii=False))
|
||||||
|
|
||||||
async def remove_subscription(self, key: str):
|
def remove_subscription(self, key: str):
|
||||||
"""取消订阅"""
|
"""取消订阅"""
|
||||||
redis_key = f"{self.prefix}subs"
|
redis_key = f"{self.prefix}subs"
|
||||||
await self.redis.hdel(redis_key, key)
|
self.redis.hdel(redis_key, key)
|
||||||
|
|
||||||
async def get_all_subscriptions(self) -> Dict[str, dict]:
|
def get_all_subscriptions(self) -> Dict[str, dict]:
|
||||||
"""获取所有订阅数据"""
|
"""获取所有订阅数据"""
|
||||||
redis_key = f"{self.prefix}subs"
|
redis_key = f"{self.prefix}subs"
|
||||||
try:
|
try:
|
||||||
raw_data = await self.redis.hgetall(redis_key)
|
raw_data = self.redis.hgetall(redis_key)
|
||||||
result = {}
|
result = {}
|
||||||
if raw_data:
|
if raw_data:
|
||||||
for k, v in raw_data.items():
|
for k, v in raw_data.items():
|
||||||
@@ -51,20 +51,20 @@ class WeatherRedisManager:
|
|||||||
logger.error(f"Redis 读取订阅失败: {e}")
|
logger.error(f"Redis 读取订阅失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
async def get_history(self, city_id: str) -> Optional[dict]:
|
def get_history(self, city_id: str) -> Optional[dict]:
|
||||||
"""获取某城市(ID)昨天的历史数据"""
|
"""获取某城市(ID)昨天的历史数据"""
|
||||||
# 注意:这里改用 city_id 作为 Key,确保唯一性
|
# 注意:这里改用 city_id 作为 Key,确保唯一性
|
||||||
redis_key = f"{self.prefix}history:{city_id}"
|
redis_key = f"{self.prefix}history:{city_id}"
|
||||||
data = await self.redis.get(redis_key)
|
data = self.redis.get(redis_key)
|
||||||
if data:
|
if data:
|
||||||
return json.loads(data)
|
return json.loads(data)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def save_history(self, city_id: str, data: dict):
|
def save_history(self, city_id: str, data: dict):
|
||||||
"""保存今天的核心数据 (Key 为 city_id)"""
|
"""保存今天的核心数据 (Key 为 city_id)"""
|
||||||
redis_key = f"{self.prefix}history:{city_id}"
|
redis_key = f"{self.prefix}history:{city_id}"
|
||||||
# 有效期 48 小时
|
# 有效期 48 小时
|
||||||
await self.redis.set(redis_key, json.dumps(data, ensure_ascii=False), ex=172800)
|
self.redis.set(redis_key, json.dumps(data, ensure_ascii=False), ex=172800)
|
||||||
|
|
||||||
|
|
||||||
# ================= 插件主体类 =================
|
# ================= 插件主体类 =================
|
||||||
@@ -198,7 +198,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
"created_at": str(datetime.datetime.now())
|
"created_at": str(datetime.datetime.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
await self.redis_manager.add_subscription(unique_id, sub_data)
|
self.redis_manager.add_subscription(unique_id, sub_data)
|
||||||
|
|
||||||
# 反馈时告诉用户标准名
|
# 反馈时告诉用户标准名
|
||||||
msg = f"✅ 订阅成功!\n已锁定城市:{city_info['adm1']} - {std_city_name}\n每天 08:00 推送早报。"
|
msg = f"✅ 订阅成功!\n已锁定城市:{city_info['adm1']} - {std_city_name}\n每天 08:00 推送早报。"
|
||||||
@@ -208,7 +208,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
# 使用 ID 获取天气,避免再次 Geo 查询
|
# 使用 ID 获取天气,避免再次 Geo 查询
|
||||||
weather_data = await self._fetch_weather_by_id(city_id)
|
weather_data = await self._fetch_weather_by_id(city_id)
|
||||||
if weather_data:
|
if weather_data:
|
||||||
await self._save_today_as_history(city_id, weather_data)
|
self._save_today_as_history(city_id, weather_data)
|
||||||
|
|
||||||
return True, "订阅成功"
|
return True, "订阅成功"
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
elif content.startswith("取消订阅"):
|
elif content.startswith("取消订阅"):
|
||||||
if not self.redis_manager: return False, "数据库不可用"
|
if not self.redis_manager: return False, "数据库不可用"
|
||||||
unique_id = f"{roomid}_{sender}" if roomid else f"private_{sender}"
|
unique_id = f"{roomid}_{sender}" if roomid else f"private_{sender}"
|
||||||
await self.redis_manager.remove_subscription(unique_id)
|
self.redis_manager.remove_subscription(unique_id)
|
||||||
await bot.send_text_message(roomid or sender, "✅ 已取消天气订阅。", sender)
|
await bot.send_text_message(roomid or sender, "✅ 已取消天气订阅。", sender)
|
||||||
return True, "取消成功"
|
return True, "取消成功"
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
async def _execute_daily_push(self):
|
async def _execute_daily_push(self):
|
||||||
"""执行全量推送 (基于 ID 聚合)"""
|
"""执行全量推送 (基于 ID 聚合)"""
|
||||||
self.LOG.info("🚀 执行每日推送...")
|
self.LOG.info("🚀 执行每日推送...")
|
||||||
subs = await self.redis_manager.get_all_subscriptions()
|
subs = self.redis_manager.get_all_subscriptions()
|
||||||
if not subs: return
|
if not subs: return
|
||||||
|
|
||||||
# 1. 按 [city_id] 聚合 (真正的去重)
|
# 1. 按 [city_id] 聚合 (真正的去重)
|
||||||
@@ -289,7 +289,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
if not api_data: continue
|
if not api_data: continue
|
||||||
|
|
||||||
# 获取 Redis 历史 (Key 也是 ID)
|
# 获取 Redis 历史 (Key 也是 ID)
|
||||||
history_data = await self.redis_manager.get_history(city_id)
|
history_data = self.redis_manager.get_history(city_id)
|
||||||
|
|
||||||
# 生成文案
|
# 生成文案
|
||||||
push_content = self._analyze_weather_change(city_name, api_data, history_data)
|
push_content = self._analyze_weather_change(city_name, api_data, history_data)
|
||||||
@@ -312,7 +312,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
self.LOG.error(f"推送给 {target_id} 失败: {send_e}")
|
self.LOG.error(f"推送给 {target_id} 失败: {send_e}")
|
||||||
|
|
||||||
# 存档
|
# 存档
|
||||||
await self._save_today_as_history(city_id, api_data)
|
self._save_today_as_history(city_id, api_data)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"处理城市ID {city_id} 推送失败: {e}")
|
self.LOG.error(f"处理城市ID {city_id} 推送失败: {e}")
|
||||||
@@ -464,7 +464,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
self.LOG.error(f"WeatherAPI(ID) 失败: {e}")
|
self.LOG.error(f"WeatherAPI(ID) 失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def _save_today_as_history(self, city_id: str, api_data: dict):
|
def _save_today_as_history(self, city_id: str, api_data: dict):
|
||||||
"""保存历史 (Key使用 ID)"""
|
"""保存历史 (Key使用 ID)"""
|
||||||
if not self.redis_manager: return
|
if not self.redis_manager: return
|
||||||
try:
|
try:
|
||||||
@@ -475,7 +475,7 @@ class WeatherPlugin(MessagePluginInterface):
|
|||||||
"tempMin": today_fc['tempMin'],
|
"tempMin": today_fc['tempMin'],
|
||||||
"text": today_fc['textDay']
|
"text": today_fc['textDay']
|
||||||
}
|
}
|
||||||
await self.redis_manager.save_history(city_id, data)
|
self.redis_manager.save_history(city_id, data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"存档失败: {e}")
|
self.LOG.error(f"存档失败: {e}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user