diff --git a/src/chat/frequency_control/frequency_control.py b/src/chat/frequency_control/frequency_control.py index 0997ec0c..dfa5a616 100644 --- a/src/chat/frequency_control/frequency_control.py +++ b/src/chat/frequency_control/frequency_control.py @@ -21,6 +21,10 @@ def init_prompt(): 如果用户觉得你的发言过于频繁,请输出"过于频繁",否则输出"正常" 如果用户觉得你的发言过少,请输出"过少",否则输出"正常" +**你只能输出以下三个词之一,不要输出任何其他文字、解释或标点:** +- 正常 +- 过于频繁 +- 过少 """, "frequency_adjust_prompt", ) @@ -103,13 +107,18 @@ class FrequencyControl: logger.info(f"频率调整 reasoning_content: {reasoning_content}") final_value_by_api = frequency_api.get_current_talk_value(self.chat_id) - if "过于频繁" in response: - logger.info(f"频率调整: 过于频繁,调整值到{final_value_by_api}") - self.talk_frequency_adjust = max(0.1, min(3.0, self.talk_frequency_adjust * 0.8)) - elif "过少" in response: - logger.info(f"频率调整: 过少,调整值到{final_value_by_api}") - self.talk_frequency_adjust = max(0.1, min(3.0, self.talk_frequency_adjust * 1.2)) - self.last_frequency_adjust_time = time.time() + + # LLM依然输出过多内容时取消本次调整。合法最多4个字,但有的模型可能会输出一些markdown换行符等,需要长度宽限 + if len(response) < 20: + if "过于频繁" in response: + logger.info(f"频率调整: 过于频繁,调整值到{final_value_by_api}") + self.talk_frequency_adjust = max(0.1, min(3.0, self.talk_frequency_adjust * 0.8)) + elif "过少" in response: + logger.info(f"频率调整: 过少,调整值到{final_value_by_api}") + self.talk_frequency_adjust = max(0.1, min(3.0, self.talk_frequency_adjust * 1.2)) + self.last_frequency_adjust_time = time.time() + else: + logger.info(f"频率调整:response不符合要求,取消本次调整") class FrequencyControlManager: """频率控制管理器,管理多个聊天流的频率控制实例""" diff --git a/src/chat/utils/statistic.py b/src/chat/utils/statistic.py index 2c4dd619..ca064044 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -519,29 +519,32 @@ class StatisticOutputTask(AsyncTask): last_all_time_stat = None - if "last_full_statistics" in local_storage: - # 如果存在上次完整统计数据,则使用该数据进行增量统计 - last_stat: Dict[str, Any] = local_storage["last_full_statistics"] # 上次完整统计数据 # type: ignore + try: + if "last_full_statistics" in local_storage: + # 如果存在上次完整统计数据,则使用该数据进行增量统计 + last_stat: Dict[str, Any] = local_storage["last_full_statistics"] # 上次完整统计数据 # type: ignore - # 修复 name_mapping 数据类型不匹配问题 - # JSON 中存储为列表,但代码期望为元组 - raw_name_mapping = last_stat["name_mapping"] - self.name_mapping = {} - for chat_id, value in raw_name_mapping.items(): - if isinstance(value, list) and len(value) == 2: - # 将列表转换为元组 - self.name_mapping[chat_id] = (value[0], value[1]) - elif isinstance(value, tuple) and len(value) == 2: - # 已经是元组,直接使用 - self.name_mapping[chat_id] = value - else: - # 数据格式不正确,跳过或使用默认值 - logger.warning(f"name_mapping 中 chat_id {chat_id} 的数据格式不正确: {value}") - continue - last_all_time_stat = last_stat["stat_data"] # 上次完整统计的统计数据 - last_stat_timestamp = datetime.fromtimestamp(last_stat["timestamp"]) # 上次完整统计数据的时间戳 - self.stat_period = [item for item in self.stat_period if item[0] != "all_time"] # 删除"所有时间"的统计时段 - self.stat_period.append(("all_time", now - last_stat_timestamp, "自部署以来的")) + # 修复 name_mapping 数据类型不匹配问题 + # JSON 中存储为列表,但代码期望为元组 + raw_name_mapping = last_stat["name_mapping"] + self.name_mapping = {} + for chat_id, value in raw_name_mapping.items(): + if isinstance(value, list) and len(value) == 2: + # 将列表转换为元组 + self.name_mapping[chat_id] = (value[0], value[1]) + elif isinstance(value, tuple) and len(value) == 2: + # 已经是元组,直接使用 + self.name_mapping[chat_id] = value + else: + # 数据格式不正确,跳过或使用默认值 + logger.warning(f"name_mapping 中 chat_id {chat_id} 的数据格式不正确: {value}") + continue + last_all_time_stat = last_stat["stat_data"] # 上次完整统计的统计数据 + last_stat_timestamp = datetime.fromtimestamp(last_stat["timestamp"]) # 上次完整统计数据的时间戳 + self.stat_period = [item for item in self.stat_period if item[0] != "all_time"] # 删除"所有时间"的统计时段 + self.stat_period.append(("all_time", now - last_stat_timestamp, "自部署以来的")) + except Exception as e: + logger.warning(f"加载上次完整统计数据失败,进行全量统计,错误信息:{e}") stat_start_timestamp = [(period[0], now - period[1]) for period in self.stat_period] diff --git a/src/llm_models/utils.py b/src/llm_models/utils.py index 5c760252..57492dce 100644 --- a/src/llm_models/utils.py +++ b/src/llm_models/utils.py @@ -29,12 +29,19 @@ def compress_messages(messages: list[Message], img_target_size: int = 1 * 1024 * :return: 转换后的图片数据 """ try: - image = Image.open(image_data) + image = Image.open(io.BytesIO(image_data)) - if image.format and (image.format.upper() in ["JPEG", "JPG", "PNG", "WEBP"]): - # 静态图像,转换为JPEG格式 + # 仅在非动图时进行格式转换 + if ( + not getattr(image, "is_animated", False) + and image.format + and (image.format.upper() in ["JPEG", "JPG", "PNG", "WEBP"]) + ): reformated_image_data = io.BytesIO() - image.save(reformated_image_data, format="JPEG", quality=95, optimize=True) + img_to_save = image + if img_to_save.mode in ("RGBA", "LA", "P"): + img_to_save = img_to_save.convert("RGB") + img_to_save.save(reformated_image_data, format="JPEG", quality=95, optimize=True) image_data = reformated_image_data.getvalue() return image_data @@ -50,20 +57,22 @@ def compress_messages(messages: list[Message], img_target_size: int = 1 * 1024 * :return: 缩放后的图片数据 """ try: - image = Image.open(image_data) + image = Image.open(io.BytesIO(image_data)) # 原始尺寸 original_size = (image.width, image.height) - # 计算新的尺寸 - new_size = (int(original_size[0] * scale), int(original_size[1] * scale)) + # 计算新的尺寸,防止为0 + new_w = max(1, int(original_size[0] * scale)) + new_h = max(1, int(original_size[1] * scale)) + new_size = (new_w, new_h) output_buffer = io.BytesIO() if getattr(image, "is_animated", False): # 动态图片,处理所有帧 frames = [] - new_size = (new_size[0] // 2, new_size[1] // 2) # 动图,缩放尺寸再打折 + new_size = (max(1, new_size[0] // 2), max(1, new_size[1] // 2)) # 动图,缩放尺寸再打折 for frame_idx in range(getattr(image, "n_frames", 1)): image.seek(frame_idx) new_frame = image.copy() @@ -83,6 +92,8 @@ def compress_messages(messages: list[Message], img_target_size: int = 1 * 1024 * else: # 静态图片,直接缩放保存 resized_image = image.resize(new_size, Image.Resampling.LANCZOS) + if resized_image.mode in ("RGBA", "LA", "P"): + resized_image = resized_image.convert("RGB") resized_image.save(output_buffer, format="JPEG", quality=95, optimize=True) return output_buffer.getvalue(), original_size, new_size