Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox_Bot into dev
This commit is contained in:
@@ -43,7 +43,6 @@ class MaiZoneRefactoredPlugin(BasePlugin):
|
|||||||
"plugin": {"enable": ConfigField(type=bool, default=True, description="是否启用插件")},
|
"plugin": {"enable": ConfigField(type=bool, default=True, description="是否启用插件")},
|
||||||
"models": {
|
"models": {
|
||||||
"text_model": ConfigField(type=str, default="maizone", description="生成文本的模型名称"),
|
"text_model": ConfigField(type=str, default="maizone", description="生成文本的模型名称"),
|
||||||
"vision_model": ConfigField(type=str, default="sf-glm-4.5v", description="识别图片的模型名称(建议使用model_config.toml中配置的视觉模型)"),
|
|
||||||
"siliconflow_apikey": ConfigField(type=str, default="", description="硅基流动AI生图API密钥"),
|
"siliconflow_apikey": ConfigField(type=str, default="", description="硅基流动AI生图API密钥"),
|
||||||
},
|
},
|
||||||
"send": {
|
"send": {
|
||||||
|
|||||||
@@ -245,14 +245,15 @@ class ContentService:
|
|||||||
image_format = kind.extension
|
image_format = kind.extension
|
||||||
image_base64 = base64.b64encode(image_bytes).decode("utf-8")
|
image_base64 = base64.b64encode(image_bytes).decode("utf-8")
|
||||||
|
|
||||||
vision_model_name = self.get_config("models.vision_model", "vlm")
|
# 优先从全局配置读取视觉模型,如果未配置,则使用默认的 "vlm"
|
||||||
|
vision_model_name = config_api.get_global_config("model.vision.default_model", "vlm")
|
||||||
|
|
||||||
# 使用 llm_api 获取模型配置,支持自动fallback到备选模型
|
# 使用 llm_api 获取模型配置
|
||||||
models = llm_api.get_available_models()
|
models = llm_api.get_available_models()
|
||||||
vision_model_config = models.get(vision_model_name)
|
vision_model_config = models.get(vision_model_name)
|
||||||
|
|
||||||
if not vision_model_config:
|
if not vision_model_config:
|
||||||
logger.error(f"未找到视觉模型配置: {vision_model_name}")
|
logger.error(f"未在 model_config.toml 中找到视觉模型配置: {vision_model_name}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
vision_model_config.temperature = 0.3
|
vision_model_config.temperature = 0.3
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class QZoneService:
|
|||||||
content_service: ContentService,
|
content_service: ContentService,
|
||||||
image_service: ImageService,
|
image_service: ImageService,
|
||||||
cookie_service: CookieService,
|
cookie_service: CookieService,
|
||||||
reply_tracker: ReplyTrackerService = None,
|
reply_tracker: ReplyTrackerService | None = None,
|
||||||
):
|
):
|
||||||
self.get_config = get_config
|
self.get_config = get_config
|
||||||
self.content_service = content_service
|
self.content_service = content_service
|
||||||
@@ -128,7 +128,8 @@ class QZoneService:
|
|||||||
target_person_id = await person_api.get_person_id_by_name(target_name)
|
target_person_id = await person_api.get_person_id_by_name(target_name)
|
||||||
if not target_person_id:
|
if not target_person_id:
|
||||||
return {"success": False, "message": f"找不到名为'{target_name}'的好友"}
|
return {"success": False, "message": f"找不到名为'{target_name}'的好友"}
|
||||||
target_qq = await person_api.get_person_value(target_person_id, "user_id")
|
person_info = await person_api.get_person_info(target_person_id)
|
||||||
|
target_qq = person_info.get("user_id")
|
||||||
if not target_qq:
|
if not target_qq:
|
||||||
return {"success": False, "message": f"好友'{target_name}'没有关联QQ号"}
|
return {"success": False, "message": f"好友'{target_name}'没有关联QQ号"}
|
||||||
|
|
||||||
@@ -155,7 +156,7 @@ class QZoneService:
|
|||||||
total_liked = 0
|
total_liked = 0
|
||||||
total_commented = 0
|
total_commented = 0
|
||||||
for feed in feeds:
|
for feed in feeds:
|
||||||
result = await self._process_single_feed(feed, api_client, target_qq, target_name)
|
result = await self._process_single_feed(feed, api_client, str(target_qq), target_name)
|
||||||
if result["liked"]:
|
if result["liked"]:
|
||||||
total_liked += 1
|
total_liked += 1
|
||||||
if result["commented"]:
|
if result["commented"]:
|
||||||
@@ -254,7 +255,7 @@ class QZoneService:
|
|||||||
if not target_qq or str(target_qq) == str(qq_account): # 确保不重复处理自己的
|
if not target_qq or str(target_qq) == str(qq_account): # 确保不重复处理自己的
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result = await self._process_single_feed(feed, api_client, target_qq, target_qq)
|
result = await self._process_single_feed(feed, api_client, str(target_qq), str(target_qq))
|
||||||
monitor_stats["total"] += 1
|
monitor_stats["total"] += 1
|
||||||
if result.get("liked"):
|
if result.get("liked"):
|
||||||
monitor_stats["liked"] += 1
|
monitor_stats["liked"] += 1
|
||||||
@@ -1151,28 +1152,28 @@ class QZoneService:
|
|||||||
|
|
||||||
like_btn = soup.find("a", class_="qz_like_btn_v3")
|
like_btn = soup.find("a", class_="qz_like_btn_v3")
|
||||||
is_liked = False
|
is_liked = False
|
||||||
if like_btn and isinstance(like_btn, bs4.Tag):
|
if isinstance(like_btn, bs4.Tag) and like_btn.get("data-islike") == "1":
|
||||||
is_liked = like_btn.get("data-islike") == "1"
|
is_liked = True
|
||||||
|
|
||||||
if is_liked:
|
if is_liked:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
text_div = soup.find("div", class_="f-info")
|
text_div = soup.find("div", class_="f-info")
|
||||||
text = text_div.get_text(strip=True) if text_div else ""
|
text = text_div.get_text(strip=True) if isinstance(text_div, bs4.Tag) else ""
|
||||||
|
|
||||||
# --- 借鉴原版插件的精确图片提取逻辑 ---
|
# --- 借鉴原版插件的精确图片提取逻辑 ---
|
||||||
image_urls = []
|
image_urls = []
|
||||||
img_box = soup.find("div", class_="img-box")
|
img_box = soup.find("div", class_="img-box")
|
||||||
if img_box:
|
if isinstance(img_box, bs4.Tag):
|
||||||
for img in img_box.find_all("img"):
|
for img in img_box.find_all("img"):
|
||||||
src = img.get("src")
|
if isinstance(img, bs4.Tag):
|
||||||
# 排除QQ空间的小图标和表情
|
src = img.get("src")
|
||||||
if src and "qzonestyle.gtimg.cn" not in src:
|
if src and isinstance(src, str) and "qzonestyle.gtimg.cn" not in src:
|
||||||
image_urls.append(src)
|
image_urls.append(src)
|
||||||
|
|
||||||
# 视频封面也视为图片
|
# 视频封面也视为图片
|
||||||
video_thumb = soup.select_one("div.video-img img")
|
video_thumb = soup.select_one("div.video-img img")
|
||||||
if video_thumb and "src" in video_thumb.attrs:
|
if isinstance(video_thumb, bs4.Tag) and "src" in video_thumb.attrs:
|
||||||
image_urls.append(video_thumb["src"])
|
image_urls.append(video_thumb["src"])
|
||||||
|
|
||||||
# 去重
|
# 去重
|
||||||
@@ -1181,11 +1182,13 @@ class QZoneService:
|
|||||||
comments = []
|
comments = []
|
||||||
comment_divs = soup.find_all("div", class_="f-single-comment")
|
comment_divs = soup.find_all("div", class_="f-single-comment")
|
||||||
for comment_div in comment_divs:
|
for comment_div in comment_divs:
|
||||||
|
if not isinstance(comment_div, bs4.Tag):
|
||||||
|
continue
|
||||||
# --- 处理主评论 ---
|
# --- 处理主评论 ---
|
||||||
author_a = comment_div.find("a", class_="f-nick")
|
author_a = comment_div.find("a", class_="f-nick")
|
||||||
content_span = comment_div.find("span", class_="f-re-con")
|
content_span = comment_div.find("span", class_="f-re-con")
|
||||||
|
|
||||||
if author_a and content_span:
|
if isinstance(author_a, bs4.Tag) and isinstance(content_span, bs4.Tag):
|
||||||
comments.append(
|
comments.append(
|
||||||
{
|
{
|
||||||
"qq_account": str(comment_div.get("data-uin", "")),
|
"qq_account": str(comment_div.get("data-uin", "")),
|
||||||
@@ -1199,21 +1202,23 @@ class QZoneService:
|
|||||||
# --- 处理这条主评论下的所有回复 ---
|
# --- 处理这条主评论下的所有回复 ---
|
||||||
reply_divs = comment_div.find_all("div", class_="f-single-re")
|
reply_divs = comment_div.find_all("div", class_="f-single-re")
|
||||||
for reply_div in reply_divs:
|
for reply_div in reply_divs:
|
||||||
|
if not isinstance(reply_div, bs4.Tag):
|
||||||
|
continue
|
||||||
reply_author_a = reply_div.find("a", class_="f-nick")
|
reply_author_a = reply_div.find("a", class_="f-nick")
|
||||||
reply_content_span = reply_div.find("span", class_="f-re-con")
|
reply_content_span = reply_div.find("span", class_="f-re-con")
|
||||||
|
|
||||||
if reply_author_a and reply_content_span:
|
if isinstance(reply_author_a, bs4.Tag) and isinstance(reply_content_span, bs4.Tag):
|
||||||
comments.append(
|
comments.append(
|
||||||
{
|
{
|
||||||
"qq_account": str(reply_div.get("data-uin", "")),
|
"qq_account": str(reply_div.get("data-uin", "")),
|
||||||
"nickname": reply_author_a.get_text(strip=True),
|
"nickname": reply_author_a.get_text(strip=True),
|
||||||
"content": reply_content_span.get_text(strip=True).lstrip(
|
"content": reply_content_span.get_text(strip=True).lstrip(
|
||||||
": "
|
": "
|
||||||
), # 移除回复内容前多余的冒号和空格
|
),
|
||||||
"comment_tid": reply_div.get("data-tid", ""),
|
"comment_tid": reply_div.get("data-tid", ""),
|
||||||
"parent_tid": reply_div.get(
|
"parent_tid": reply_div.get(
|
||||||
"data-parent-tid", comment_div.get("data-tid", "")
|
"data-parent-tid", comment_div.get("data-tid", "")
|
||||||
), # 如果没有父ID,则将父ID设为主评论ID
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ class ReplyTrackerService:
|
|||||||
try:
|
try:
|
||||||
if self.reply_record_file.exists():
|
if self.reply_record_file.exists():
|
||||||
try:
|
try:
|
||||||
with open(self.reply_record_file, encoding="utf-8") as f:
|
with open(self.reply_record_file, "rb") as f:
|
||||||
file_content = f.read().strip()
|
file_content = f.read()
|
||||||
if not file_content: # 文件为空
|
if not file_content.strip(): # 文件为空
|
||||||
logger.warning("回复记录文件为空,将创建新的记录")
|
logger.warning("回复记录文件为空,将创建新的记录")
|
||||||
self.replied_comments = {}
|
self.replied_comments = {}
|
||||||
return
|
return
|
||||||
@@ -118,8 +118,8 @@ class ReplyTrackerService:
|
|||||||
temp_file = self.reply_record_file.with_suffix(".tmp")
|
temp_file = self.reply_record_file.with_suffix(".tmp")
|
||||||
|
|
||||||
# 先写入临时文件
|
# 先写入临时文件
|
||||||
with open(temp_file, "w", encoding="utf-8"):
|
with open(temp_file, "wb") as f:
|
||||||
orjson.dumps(self.replied_comments, option=orjson.OPT_INDENT_2 | orjson.OPT_NON_STR_KEYS).decode("utf-8")
|
f.write(orjson.dumps(self.replied_comments, option=orjson.OPT_INDENT_2 | orjson.OPT_NON_STR_KEYS))
|
||||||
|
|
||||||
# 如果写入成功,重命名为正式文件
|
# 如果写入成功,重命名为正式文件
|
||||||
if temp_file.stat().st_size > 0: # 确保写入成功
|
if temp_file.stat().st_size > 0: # 确保写入成功
|
||||||
|
|||||||
Reference in New Issue
Block a user