删除 5m以上缓存图片

This commit is contained in:
SengokuCola
2025-03-04 23:28:40 +08:00
parent ba69a84b19
commit 438e7e9e9e
4 changed files with 104 additions and 47 deletions

View File

@@ -235,6 +235,7 @@ class EmojiManager:
except Exception as e: except Exception as e:
print(f"\033[1;31m[错误]\033[0m 获取标签失败: {str(e)}") print(f"\033[1;31m[错误]\033[0m 获取标签失败: {str(e)}")
return "skip"
print(f"\033[1;32m[调试信息]\033[0m 使用默认标签: neutral") print(f"\033[1;32m[调试信息]\033[0m 使用默认标签: neutral")
return "skip" # 默认标签 return "skip" # 默认标签
@@ -249,12 +250,20 @@ class EmojiManager:
files_to_process = [f for f in os.listdir(emoji_dir) if f.endswith('.jpg')] files_to_process = [f for f in os.listdir(emoji_dir) if f.endswith('.jpg')]
for filename in files_to_process: for filename in files_to_process:
image_path = os.path.join(emoji_dir, filename)
# 检查文件大小
file_size = os.path.getsize(image_path)
if file_size > 5 * 1024 * 1024: # 5MB
print(f"\033[1;33m[警告]\033[0m 表情包文件过大 ({file_size/1024/1024:.2f}MB),删除: {filename}")
os.remove(image_path)
continue
# 检查是否已经注册过 # 检查是否已经注册过
existing_emoji = self.db.db['emoji'].find_one({'filename': filename}) existing_emoji = self.db.db['emoji'].find_one({'filename': filename})
if existing_emoji: if existing_emoji:
continue continue
image_path = os.path.join(emoji_dir, filename)
# 读取图片数据 # 读取图片数据
with open(image_path, 'rb') as f: with open(image_path, 'rb') as f:
image_data = f.read() image_data = f.read()

View File

@@ -72,7 +72,7 @@ class Message:
#将详细翻译为详细可读文本 #将详细翻译为详细可读文本
time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.time)) time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.time))
try: try:
name = f"[({self.user_id}){self.user_nickname}]{self.user_cardname}" name = f"{self.user_nickname}(ta的昵称:{self.user_cardname},ta的id:{self.user_id})"
except: except:
name = self.user_nickname or f"用户{self.user_id}" name = self.user_nickname or f"用户{self.user_id}"
content = self.processed_plain_text content = self.processed_plain_text

View File

@@ -6,32 +6,26 @@ import os
from ...common.database import Database from ...common.database import Database
import zlib # 用于 CRC32 import zlib # 用于 CRC32
import base64 import base64
from .config import global_config
from nonebot import get_driver from nonebot import get_driver
driver = get_driver() driver = get_driver()
config = driver.config config = driver.config
def storage_image(image_data: bytes,type: str, max_size: int = 200) -> bytes:
if type == 'image':
return storage_compress_image(image_data, max_size)
elif type == 'emoji':
return storage_emoji(image_data)
else:
raise ValueError(f"不支持的图片类型: {type}")
def storage_compress_image(base64_data: str, max_size: int = 200) -> str:
def storage_compress_image(image_data: bytes, max_size: int = 200) -> bytes:
""" """
压缩图片到指定大小单位KB并在数据库中记录图片信息 压缩base64格式的图片到指定大小单位KB并在数据库中记录图片信息
Args: Args:
image_data: 图片字节数据 base64_data: base64编码的图片数据
group_id: 群组ID
user_id: 用户ID
max_size: 最大文件大小KB max_size: 最大文件大小KB
Returns:
str: 压缩后的base64图片数据
""" """
try: try:
# 将base64转换为字节数据
image_data = base64.b64decode(base64_data)
# 使用 CRC32 计算哈希值 # 使用 CRC32 计算哈希值
hash_value = format(zlib.crc32(image_data) & 0xFFFFFFFF, 'x') hash_value = format(zlib.crc32(image_data) & 0xFFFFFFFF, 'x')
@@ -41,11 +35,11 @@ def storage_compress_image(image_data: bytes, max_size: int = 200) -> bytes:
# 连接数据库 # 连接数据库
db = Database( db = Database(
host= config.mongodb_host, host=config.mongodb_host,
port= int(config.mongodb_port), port=int(config.mongodb_port),
db_name= config.database_name, db_name=config.database_name,
username= config.mongodb_username, username=config.mongodb_username,
password= config.mongodb_password, password=config.mongodb_password,
auth_source=config.mongodb_auth_source auth_source=config.mongodb_auth_source
) )
@@ -55,14 +49,14 @@ def storage_compress_image(image_data: bytes, max_size: int = 200) -> bytes:
if existing_image: if existing_image:
print(f"\033[1;33m[提示]\033[0m 发现重复图片,使用已存在的文件: {existing_image['path']}") print(f"\033[1;33m[提示]\033[0m 发现重复图片,使用已存在的文件: {existing_image['path']}")
return image_data return base64_data
# 将字节数据转换为图片对象 # 将字节数据转换为图片对象
img = Image.open(io.BytesIO(image_data)) img = Image.open(io.BytesIO(image_data))
# 如果是动图,直接返回原图 # 如果是动图,直接返回原图
if getattr(img, 'is_animated', False): if getattr(img, 'is_animated', False):
return image_data return base64_data
# 计算当前大小KB # 计算当前大小KB
current_size = len(image_data) / 1024 current_size = len(image_data) / 1024
@@ -127,14 +121,16 @@ def storage_compress_image(image_data: bytes, max_size: int = 200) -> bytes:
except Exception as db_error: except Exception as db_error:
print(f"\033[1;31m[错误]\033[0m 数据库操作失败: {str(db_error)}") print(f"\033[1;31m[错误]\033[0m 数据库操作失败: {str(db_error)}")
return compressed_data # 将压缩后的数据转换为base64
compressed_base64 = base64.b64encode(compressed_data).decode('utf-8')
return compressed_base64
except Exception as e: except Exception as e:
print(f"\033[1;31m[错误]\033[0m 压缩图片失败: {str(e)}") print(f"\033[1;31m[错误]\033[0m 压缩图片失败: {str(e)}")
import traceback import traceback
print(traceback.format_exc()) print(traceback.format_exc())
return image_data return base64_data
def storage_emoji(image_data: bytes) -> bytes: def storage_emoji(image_data: bytes) -> bytes:
""" """
@@ -215,4 +211,48 @@ def storage_image(image_data: bytes) -> bytes:
except Exception as e: except Exception as e:
print(f"\033[1;31m[错误]\033[0m 保存图片失败: {str(e)}") print(f"\033[1;31m[错误]\033[0m 保存图片失败: {str(e)}")
return image_data return image_data
def compress_base64_image_by_scale(base64_data: str, scale: float = 0.5) -> str:
"""按比例压缩base64格式的图片
Args:
base64_data: base64编码的图片数据
scale: 压缩比例0-1之间的浮点数
Returns:
str: 压缩后的base64图片数据
"""
try:
# 将base64转换为字节数据
image_data = base64.b64decode(base64_data)
# 将字节数据转换为图片对象
img = Image.open(io.BytesIO(image_data))
# 如果是动图,直接返回原图
if getattr(img, 'is_animated', False):
return base64_data
# 计算新的尺寸
new_width = int(img.width * scale)
new_height = int(img.height * scale)
# 缩放图片
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 转换为RGB模式去除透明通道
if img.mode in ('RGBA', 'P'):
img = img.convert('RGB')
# 保存压缩后的图片
output = io.BytesIO()
img.save(output, format='JPEG', quality=85, optimize=True)
compressed_data = output.getvalue()
# 转换回base64
return base64.b64encode(compressed_data).decode('utf-8')
except Exception as e:
print(f"\033[1;31m[错误]\033[0m 压缩图片失败: {str(e)}")
import traceback
print(traceback.format_exc())
return base64_data

View File

@@ -6,6 +6,7 @@ from typing import Tuple, Union
from nonebot import get_driver from nonebot import get_driver
from loguru import logger from loguru import logger
from ..chat.config import global_config from ..chat.config import global_config
from ..chat.utils_image import compress_base64_image_by_scale
driver = get_driver() driver = get_driver()
config = driver.config config = driver.config
@@ -82,27 +83,28 @@ class LLM_request:
} }
# 构建请求体 # 构建请求体
data = { def build_request_data(img_base64: str):
"model": self.model_name, return {
"messages": [ "model": self.model_name,
{ "messages": [
"role": "user", {
"content": [ "role": "user",
{ "content": [
"type": "text", {
"text": prompt "type": "text",
}, "text": prompt
{ },
"type": "image_url", {
"image_url": { "type": "image_url",
"url": f"data:image/jpeg;base64,{image_base64}" "image_url": {
"url": f"data:image/jpeg;base64,{img_base64}"
}
} }
} ]
] }
} ],
], **self.params
**self.params }
}
# 发送请求到完整的chat/completions端点 # 发送请求到完整的chat/completions端点
api_url = f"{self.base_url.rstrip('/')}/chat/completions" api_url = f"{self.base_url.rstrip('/')}/chat/completions"
@@ -110,9 +112,11 @@ class LLM_request:
max_retries = 3 max_retries = 3
base_wait_time = 15 base_wait_time = 15
current_image_base64 = image_base64
for retry in range(max_retries): for retry in range(max_retries):
try: try:
data = build_request_data(current_image_base64)
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.post(api_url, headers=headers, json=data) as response: async with session.post(api_url, headers=headers, json=data) as response:
if response.status == 429: if response.status == 429:
@@ -120,6 +124,10 @@ class LLM_request:
logger.warning(f"遇到请求限制(429),等待{wait_time}秒后重试...") logger.warning(f"遇到请求限制(429),等待{wait_time}秒后重试...")
await asyncio.sleep(wait_time) await asyncio.sleep(wait_time)
continue continue
elif response.status == 413:
logger.warning("图片太大(413),尝试压缩...")
current_image_base64 = compress_base64_image_by_scale(current_image_base64)
continue
response.raise_for_status() # 检查其他响应状态 response.raise_for_status() # 检查其他响应状态