feat(notify): 添加发送到群聊

This commit is contained in:
2026-04-29 23:26:14 +08:00
parent 081f63c1d4
commit bb923ee2b3
6 changed files with 95 additions and 8 deletions

View File

@@ -3,4 +3,7 @@ UID=
USER_NO=
SCHOOL_ACCOUNT=
USER_NAME=
WECHAT_COMANY_BOT_KEY=
WECHAT_COMANY_BOT_KEY=
WEBHOOK_API_URL=
WEBHOOK_GROUP_ID=
WEBHOOK_API_TOKEN=

4
.gitignore vendored
View File

@@ -1,3 +1,5 @@
__pycache__
data
fonts/*.ttf
fonts/*.ttf
.env
.vscode

View File

@@ -58,7 +58,7 @@
- 安装依赖
```sh
pip install aiosqlite apscheduler httpx matplotlib dotenv
pip install aiosqlite apscheduler httpx matplotlib dotenv uvicorn
```
- 通过 `scheduler.py` 修改监控时长配置(不懂的请问 AI

View File

@@ -17,3 +17,8 @@ USER_NAME = os.getenv("USER_NAME", "张三") # 姓名
WECHAT_COMANY_BOT_KEY = os.getenv(
"WECHAT_COMANY_BOT_KEY", "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
)
# Webhook 服务相关配置
WEBHOOK_API_URL = os.getenv("WEBHOOK_API_URL", "http://127.0.0.1:8081")
WEBHOOK_API_TOKEN = os.getenv("WEBHOOK_API_TOKEN", "xxx")
WEBHOOK_GROUP_ID = os.getenv("WEBHOOK_GROUP_ID", "")

View File

@@ -1,5 +1,6 @@
import httpx
import config
from pathlib import Path
async def send_image(base64_str: str, md5: str):
@@ -10,3 +11,71 @@ async def send_image(base64_str: str, md5: str):
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(url, json=payload)
resp.raise_for_status()
async def upload_file(file_path: str, filename: str = "None") -> str:
"""
上传文件到 webhook 服务的 /upload 端点
Args:
file_path: 本地文件路径
filename: 上传时的文件名,不指定则使用原文件名
Returns:
远程文件路径
"""
if filename is None:
filename = Path(file_path).name
url = f"{config.WEBHOOK_API_URL}/upload"
headers = {"Authorization": f"Bearer {config.WEBHOOK_API_TOKEN}"}
with open(file_path, "rb") as f:
files = {"file": (filename, f)}
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(url, files=files, headers=headers)
resp.raise_for_status()
data = resp.json()
return data.get("path", data.get("files", [None])[0])
async def send_webhook(group_id: str, file_url: str) -> dict:
"""
发送 webhook 请求通知文件
Args:
group_id: 群组 ID
file_url: 远程文件路径
Returns:
API 响应字典
"""
url = f"{config.WEBHOOK_API_URL}/webhook"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {config.WEBHOOK_API_TOKEN}",
}
payload = {"group_id": group_id, "url": file_url, "type": "image"}
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(url, json=payload, headers=headers)
resp.raise_for_status()
return resp.json()
async def upload_and_notify(file_path: str, group_id: str, filename: str = "") -> dict:
"""
上传文件并发送 webhook 通知(组合函数)
Args:
file_path: 本地文件路径
group_id: 群组 ID
filename: 上传时的文件名,不指定则使用原文件名
Returns:
API 响应字典
"""
remote_path = await upload_file(file_path, filename)
result = await send_webhook(group_id, remote_path)
return result

View File

@@ -4,7 +4,7 @@ import logging
import base64
import hashlib
from notify.wechat_company import send_image
from notify.wechat_company import send_image, upload_and_notify
from services.render import render_ammeter_chart, render_water_chart
from services import collector
import config
@@ -122,8 +122,11 @@ class SD:
ele_img_path = await render_ammeter_chart()
if ele_img_path:
logger.info("生成电表图表成功: %s", ele_img_path)
ele_b64, ele_md5 = image_to_base64_md5(ele_img_path)
await send_image(ele_b64, ele_md5)
# ele_b64, ele_md5 = image_to_base64_md5(ele_img_path)
# await send_image(ele_b64, ele_md5)
await upload_and_notify(
ele_img_path, config.WEBHOOK_GROUP_ID, ele_img_path.split("/")[-1]
)
logger.info("电表图表推送完成")
else:
logger.warning("未生成电表图表,跳过推送")
@@ -131,8 +134,13 @@ class SD:
water_img_path = await render_water_chart()
if water_img_path:
logger.info("生成水表图表成功: %s", water_img_path)
water_b64, water_md5 = image_to_base64_md5(water_img_path)
await send_image(water_b64, water_md5)
# water_b64, water_md5 = image_to_base64_md5(water_img_path)
# await send_image(water_b64, water_md5)
await upload_and_notify(
water_img_path,
config.WEBHOOK_GROUP_ID,
water_img_path.split("/")[-1],
)
logger.info("水表图表推送完成")
else:
logger.warning("未生成水表图表,跳过推送")