diff --git a/changelogs/changelog.md b/changelogs/changelog.md index d9759ea11..a3239ff36 100644 --- a/changelogs/changelog.md +++ b/changelogs/changelog.md @@ -1,14 +1,13 @@ # Changelog -## [0.6.0] - 2025-3-30 +## [0.6.0] - 2025-4-4 ### 🌟 核心功能增强 #### 架构重构 - 将MaiBot重构为MaiCore独立智能体 - 移除NoneBot相关代码,改为插件方式与NoneBot对接 -- 精简代码结构,优化文件夹组织 -- 新增详细统计系统 #### 思维流系统 +- 提供两种聊天逻辑,思维流聊天(ThinkFlowChat)和推理聊天(ReasoningChat) - 新增思维流作为实验功能 - 思维流大核+小核架构 - 思维流回复意愿模式 @@ -21,6 +20,8 @@ #### 回复系统 - 优化回复逻辑,添加回复前思考机制 - 移除推理模型在回复中的使用 +- 更改了回复引用的逻辑,从基于时间改为基于新消息 +- 提供私聊的PFC模式,可以进行有目的,自由多轮对话 #### 记忆系统优化 - 优化记忆抽取策略 @@ -31,6 +32,13 @@ - 修复relationship_value类型错误 - 优化关系管理系统 - 改进关系值计算方式 +- 修复并重启了关系系统 + +#### 表情包系统 +- 可以识别gif表情包 +- 修复了表情包的注册,获取和发送逻辑 +- 表情包增加存储上限 +- 自动清理缓存图片 ### 💻 系统架构优化 #### 配置系统改进 @@ -83,6 +91,7 @@ - 优化cmd清理功能 - 改进LLM使用统计 - 优化记忆处理效率 +- 增加了调试信息 ### 📚 文档更新 - 更新README.md内容 @@ -93,6 +102,7 @@ ### 🔧 其他改进 - 新增神秘小测验功能 +- 新增详细统计系统 - 新增人格测评模型 - 优化表情包审查功能 - 改进消息转发处理 @@ -111,8 +121,6 @@ 5. 加强WebUI功能 6. 完善部署文档 - - ## [0.5.15] - 2025-3-17 ### 🌟 核心功能增强 #### 关系系统升级 diff --git a/changelogs/changelog_dev.md b/changelogs/changelog_dev.md index a776b361f..acfb7e03f 100644 --- a/changelogs/changelog_dev.md +++ b/changelogs/changelog_dev.md @@ -1,4 +1,6 @@ 这里放置了测试版本的细节更新 +## [test-0.6.0-snapshot-9] - 2025-4-4 +- 可以识别gif表情包 ## [test-0.6.0-snapshot-8] - 2025-4-3 - 修复了表情包的注册,获取和发送逻辑 diff --git a/src/plugins/chat/utils_image.py b/src/plugins/chat/utils_image.py index f19fedfdd..598f26b6c 100644 --- a/src/plugins/chat/utils_image.py +++ b/src/plugins/chat/utils_image.py @@ -5,6 +5,8 @@ import hashlib from typing import Optional from PIL import Image import io +import math +import numpy as np from ...common.database import db @@ -112,8 +114,13 @@ class ImageManager: return f"[表情包:{cached_description}]" # 调用AI获取描述 - prompt = "这是一个表情包,使用中文简洁的描述一下表情包的内容和表情包所表达的情感" - description, _ = await self._llm.generate_response_for_image(prompt, image_base64, image_format) + if image_format == "gif" or image_format == "GIF": + image_base64 = self.transform_gif(image_base64) + prompt = "这是一个动态图表情包,每一张图代表了动态图的某一帧,黑色背景代表透明,使用中文简洁的描述一下表情包的内容和表达的情感,简短一些" + description, _ = await self._llm.generate_response_for_image(prompt, image_base64, "jpg") + else: + prompt = "这是一个表情包,使用中文简洁的描述一下表情包的内容和表情包所表达的情感" + description, _ = await self._llm.generate_response_for_image(prompt, image_base64, image_format) cached_description = self._get_description_from_db(image_hash, "emoji") if cached_description: @@ -221,6 +228,72 @@ class ImageManager: logger.error(f"获取图片描述失败: {str(e)}") return "[图片]" + def transform_gif(self, gif_base64: str) -> str: + """将GIF转换为水平拼接的静态图像 + + Args: + gif_base64: GIF的base64编码字符串 + + Returns: + str: 拼接后的JPG图像的base64编码字符串 + """ + try: + # 解码base64 + gif_data = base64.b64decode(gif_base64) + gif = Image.open(io.BytesIO(gif_data)) + + # 收集所有帧 + frames = [] + try: + while True: + gif.seek(len(frames)) + frame = gif.convert('RGB') + frames.append(frame.copy()) + except EOFError: + pass + + if not frames: + raise ValueError("No frames found in GIF") + + # 计算需要抽取的帧的索引 + total_frames = len(frames) + if total_frames <= 15: + selected_frames = frames + else: + # 均匀抽取10帧 + indices = [int(i * (total_frames - 1) / 14) for i in range(15)] + selected_frames = [frames[i] for i in indices] + + # 获取单帧的尺寸 + frame_width, frame_height = selected_frames[0].size + + # 计算目标尺寸,保持宽高比 + target_height = 200 # 固定高度 + target_width = int((target_height / frame_height) * frame_width) + + # 调整所有帧的大小 + resized_frames = [frame.resize((target_width, target_height), Image.Resampling.LANCZOS) + for frame in selected_frames] + + # 创建拼接图像 + total_width = target_width * len(resized_frames) + combined_image = Image.new('RGB', (total_width, target_height)) + + # 水平拼接图像 + for idx, frame in enumerate(resized_frames): + combined_image.paste(frame, (idx * target_width, 0)) + + # 转换为base64 + buffer = io.BytesIO() + combined_image.save(buffer, format='JPEG', quality=85) + result_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8') + + return result_base64 + + except Exception as e: + logger.error(f"GIF转换失败: {str(e)}") + return None + # 创建全局单例 image_manager = ImageManager()