Merge branch 'debug' into debug
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -11,7 +11,6 @@ class WillingManager:
|
|||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(3)
|
await asyncio.sleep(3)
|
||||||
for group_id in self.group_reply_willing:
|
for group_id in self.group_reply_willing:
|
||||||
# 每分钟衰减10%的回复意愿
|
|
||||||
self.group_reply_willing[group_id] = max(0, self.group_reply_willing[group_id] * 0.6)
|
self.group_reply_willing[group_id] = max(0, self.group_reply_willing[group_id] * 0.6)
|
||||||
|
|
||||||
def get_willing(self, group_id: int) -> float:
|
def get_willing(self, group_id: int) -> float:
|
||||||
@@ -26,13 +25,7 @@ class WillingManager:
|
|||||||
"""改变指定群组的回复意愿并返回回复概率"""
|
"""改变指定群组的回复意愿并返回回复概率"""
|
||||||
current_willing = self.group_reply_willing.get(group_id, 0)
|
current_willing = self.group_reply_willing.get(group_id, 0)
|
||||||
|
|
||||||
print(f"初始意愿: {current_willing}")
|
# print(f"初始意愿: {current_willing}")
|
||||||
|
|
||||||
# if topic and current_willing < 1:
|
|
||||||
# current_willing += 0.2
|
|
||||||
# elif topic:
|
|
||||||
# current_willing += 0.05
|
|
||||||
|
|
||||||
if is_mentioned_bot and current_willing < 1.0:
|
if is_mentioned_bot and current_willing < 1.0:
|
||||||
current_willing += 0.9
|
current_willing += 0.9
|
||||||
print(f"被提及, 当前意愿: {current_willing}")
|
print(f"被提及, 当前意愿: {current_willing}")
|
||||||
@@ -57,11 +50,10 @@ class WillingManager:
|
|||||||
|
|
||||||
if group_id in config.talk_frequency_down_groups:
|
if group_id in config.talk_frequency_down_groups:
|
||||||
reply_probability = reply_probability / 3.5
|
reply_probability = reply_probability / 3.5
|
||||||
|
|
||||||
# if is_mentioned_bot and user_id == int(1026294844):
|
|
||||||
# reply_probability = 1
|
|
||||||
|
|
||||||
reply_probability = min(reply_probability, 1)
|
reply_probability = min(reply_probability, 1)
|
||||||
|
if reply_probability < 0.1:
|
||||||
|
reply_probability = 0.1
|
||||||
return reply_probability
|
return reply_probability
|
||||||
|
|
||||||
def change_reply_willing_sent(self, group_id: int):
|
def change_reply_willing_sent(self, group_id: int):
|
||||||
|
|||||||
@@ -7,6 +7,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
|
||||||
@@ -84,27 +85,29 @@ 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"
|
||||||
@@ -112,9 +115,13 @@ 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:
|
||||||
@@ -123,6 +130,11 @@ class LLM_request:
|
|||||||
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() # 检查其他响应状态
|
||||||
|
|
||||||
result = await response.json()
|
result = await response.json()
|
||||||
|
|||||||
Reference in New Issue
Block a user