From 7d448c5fdc40ec555cd3120ae16c917e98e3fbcf Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Tue, 15 Jul 2025 20:29:06 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=8F=AF=E6=8E=A5=E5=8F=97=20scre?= =?UTF-8?q?en=20seg=E6=9D=A5=E8=AF=BB=E5=B1=8F=E5=B9=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + scripts/info_extraction.py | 2 +- src/chat/message_receive/message.py | 5 + .../mais4u_chat/SUPERCHAT_MANAGER_README.md | 135 +++++++++++++++++- src/mais4u/mais4u_chat/context_web_manager.py | 6 +- src/mais4u/mais4u_chat/s4u_msg_processor.py | 13 +- src/mais4u/mais4u_chat/s4u_prompt.py | 7 +- src/mais4u/mais4u_chat/screen_manager.py | 14 ++ src/mais4u/mais4u_chat/super_chat_manager.py | 1 - 9 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 src/mais4u/mais4u_chat/screen_manager.py diff --git a/.gitignore b/.gitignore index 15a2d5739..bfd834a72 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,8 @@ config/lpmm_config.toml.bak (临时版)麦麦开始学习.bat src/plugins/utils/statistic.py CLAUDE.md +s4u.s4u +s4u.s4u1 # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/scripts/info_extraction.py b/scripts/info_extraction.py index 7370d98d8..90f0c80ea 100644 --- a/scripts/info_extraction.py +++ b/scripts/info_extraction.py @@ -24,7 +24,7 @@ from rich.progress import ( SpinnerColumn, TextColumn, ) -from raw_data_preprocessor import RAW_DATA_PATH, process_multi_files, load_raw_data +from raw_data_preprocessor import RAW_DATA_PATH, load_raw_data from src.config.config import global_config from src.llm_models.utils_model import LLMRequest diff --git a/src/chat/message_receive/message.py b/src/chat/message_receive/message.py index e3abf62c1..ddb564a6f 100644 --- a/src/chat/message_receive/message.py +++ b/src/chat/message_receive/message.py @@ -190,6 +190,7 @@ class MessageRecvS4U(MessageRecv): self.superchat_info = None self.superchat_price = None self.superchat_message_text = None + self.is_screen = False async def process(self) -> None: self.processed_plain_text = await self._process_message_segments(self.message_segment) @@ -264,6 +265,10 @@ class MessageRecvS4U(MessageRecv): self.processed_plain_text += f"(注意:这是一条超级弹幕信息,价值{self.superchat_price}元,请你认真回复)" return self.processed_plain_text + elif segment.type == "screen": + self.is_screen = True + self.screen_info = segment.data + return "屏幕信息" else: return "" except Exception as e: diff --git a/src/mais4u/mais4u_chat/SUPERCHAT_MANAGER_README.md b/src/mais4u/mais4u_chat/SUPERCHAT_MANAGER_README.md index 0519ecba6..359a00ef6 100644 --- a/src/mais4u/mais4u_chat/SUPERCHAT_MANAGER_README.md +++ b/src/mais4u/mais4u_chat/SUPERCHAT_MANAGER_README.md @@ -1 +1,134 @@ - \ No newline at end of file +# SuperChat管理器使用说明 + +## 概述 + +SuperChat管理器是用于管理和跟踪超级弹幕消息的核心组件。它能够根据SuperChat的金额自动设置不同的存活时间,并提供多种格式的字符串构建功能。 + +## 主要功能 + +### 1. 自动记录SuperChat +当收到SuperChat消息时,管理器会自动记录以下信息: +- 用户ID和昵称 +- 平台信息 +- 聊天ID +- SuperChat金额和消息内容 +- 时间戳和过期时间 +- 群组名称(如果适用) + +### 2. 基于金额的存活时间 + +SuperChat的存活时间根据金额阶梯设置: + +| 金额范围 | 存活时间 | +|---------|---------| +| ≥500元 | 4小时 | +| 200-499元 | 2小时 | +| 100-199元 | 1小时 | +| 50-99元 | 30分钟 | +| 20-49元 | 15分钟 | +| 10-19元 | 10分钟 | +| <10元 | 5分钟 | + +### 3. 自动清理 +管理器每30秒自动检查并清理过期的SuperChat记录,保持内存使用的高效性。 + +## 使用方法 + +### 基本用法 + +```python +from src.mais4u.mais4u_chat.super_chat_manager import get_super_chat_manager + +# 获取全局管理器实例 +super_chat_manager = get_super_chat_manager() + +# 添加SuperChat(通常在消息处理时自动调用) +await super_chat_manager.add_superchat(message) + +# 获取指定聊天的SuperChat显示字符串 +display_string = super_chat_manager.build_superchat_display_string(chat_id, max_count=10) + +# 获取摘要信息 +summary = super_chat_manager.build_superchat_summary_string(chat_id) + +# 获取统计信息 +stats = super_chat_manager.get_superchat_statistics(chat_id) +``` + +### 结合S4UChat使用 + +```python +from src.mais4u.mais4u_chat.s4u_chat import get_s4u_chat_manager + +# 获取S4UChat实例 +s4u_manager = get_s4u_chat_manager() +s4u_chat = s4u_manager.get_or_create_chat(chat_stream) + +# 便捷方法获取SuperChat信息 +display_string = s4u_chat.get_superchat_display_string(max_count=10) +summary = s4u_chat.get_superchat_summary_string() +stats = s4u_chat.get_superchat_statistics() +``` + +## API 参考 + +### SuperChatManager类 + +#### 主要方法 + +- `add_superchat(message: MessageRecvS4U)`: 添加SuperChat记录 +- `get_superchats_by_chat(chat_id: str)`: 获取指定聊天的有效SuperChat列表 +- `build_superchat_display_string(chat_id: str, max_count: int = 10)`: 构建显示字符串 +- `build_superchat_summary_string(chat_id: str)`: 构建摘要字符串 +- `get_superchat_statistics(chat_id: str)`: 获取统计信息 + +#### 输出格式示例 + +**显示字符串格式:** +``` +📢 当前有效超级弹幕: +1. 【100元】用户名: 消息内容 (剩余25分30秒) +2. 【50元】用户名: 消息内容 (剩余10分15秒) +... 还有3条SuperChat +``` + +**摘要字符串格式:** +``` +当前有5条超级弹幕,总金额350元,最高单笔100元 +``` + +**统计信息格式:** +```python +{ + "count": 5, + "total_amount": 350.0, + "average_amount": 70.0, + "highest_amount": 100.0, + "lowest_amount": 20.0 +} +``` + +### S4UChat扩展方法 + +- `get_superchat_display_string(max_count: int = 10)`: 获取当前聊天的SuperChat显示字符串 +- `get_superchat_summary_string()`: 获取当前聊天的SuperChat摘要字符串 +- `get_superchat_statistics()`: 获取当前聊天的SuperChat统计信息 + +## 集成说明 + +SuperChat管理器已经集成到S4U聊天系统中: + +1. **自动处理**: 当S4UChat收到SuperChat消息时,会自动调用管理器记录 +2. **内存管理**: 管理器会自动清理过期的SuperChat,无需手动管理 +3. **全局单例**: 使用全局单例模式,确保所有聊天共享同一个管理器实例 + +## 注意事项 + +1. SuperChat管理器是全局单例,在应用程序整个生命周期中保持运行 +2. 过期时间基于消息金额自动计算,无需手动设置 +3. 管理器会自动处理异常情况,如无效的价格格式等 +4. 清理任务在后台异步运行,不会阻塞主要功能 + +## 示例文件 + +参考 `superchat_example.py` 文件查看完整的使用示例。 \ No newline at end of file diff --git a/src/mais4u/mais4u_chat/context_web_manager.py b/src/mais4u/mais4u_chat/context_web_manager.py index 68e5822c6..8c6cde2c2 100644 --- a/src/mais4u/mais4u_chat/context_web_manager.py +++ b/src/mais4u/mais4u_chat/context_web_manager.py @@ -499,7 +499,7 @@ class ContextWebManager: async def get_contexts_handler(self, request): """获取上下文API""" all_context_msgs = [] - for chat_id, contexts in self.contexts.items(): + for _chat_id, contexts in self.contexts.items(): all_context_msgs.extend(list(contexts)) # 按时间排序,最新的在最后 @@ -609,7 +609,7 @@ class ContextWebManager: async def send_contexts_to_websocket(self, ws: web.WebSocketResponse): """向单个WebSocket发送上下文数据""" all_context_msgs = [] - for chat_id, contexts in self.contexts.items(): + for _chat_id, contexts in self.contexts.items(): all_context_msgs.extend(list(contexts)) # 按时间排序,最新的在最后 @@ -628,7 +628,7 @@ class ContextWebManager: return all_context_msgs = [] - for chat_id, contexts in self.contexts.items(): + for _chat_id, contexts in self.contexts.items(): all_context_msgs.extend(list(contexts)) # 按时间排序,最新的在最后 diff --git a/src/mais4u/mais4u_chat/s4u_msg_processor.py b/src/mais4u/mais4u_chat/s4u_msg_processor.py index b1e1da43c..47bd294c2 100644 --- a/src/mais4u/mais4u_chat/s4u_msg_processor.py +++ b/src/mais4u/mais4u_chat/s4u_msg_processor.py @@ -15,6 +15,7 @@ from src.mais4u.mais4u_chat.s4u_mood_manager import mood_manager from src.mais4u.mais4u_chat.s4u_watching_manager import watching_manager from src.mais4u.mais4u_chat.context_web_manager import get_context_web_manager from src.mais4u.mais4u_chat.gift_manager import gift_manager +from src.mais4u.mais4u_chat.screen_manager import screen_manager from .s4u_chat import get_s4u_chat_manager @@ -95,8 +96,12 @@ class S4UMessageProcessor: # 处理礼物消息,如果消息被暂存则停止当前处理流程 if not skip_gift_debounce and not await self.handle_if_gift(message): return - await self.check_if_fake_gift(message) + + # 处理屏幕消息 + if await self.handle_screen_message(message): + return + await self.storage.store_message(message, chat) @@ -128,6 +133,12 @@ class S4UMessageProcessor: else: logger.info(f"[S4U]{userinfo.user_nickname}:{message.processed_plain_text}") + async def handle_screen_message(self, message: MessageRecvS4U): + if message.is_screen: + screen_manager.set_screen(message.screen_info) + return True + return False + async def check_if_fake_gift(self, message: MessageRecvS4U) -> bool: """检查消息是否为假礼物""" if message.is_gift: diff --git a/src/mais4u/mais4u_chat/s4u_prompt.py b/src/mais4u/mais4u_chat/s4u_prompt.py index 2598961bc..261c5306b 100644 --- a/src/mais4u/mais4u_chat/s4u_prompt.py +++ b/src/mais4u/mais4u_chat/s4u_prompt.py @@ -15,6 +15,7 @@ from src.person_info.person_info import get_person_info_manager from src.person_info.relationship_manager import get_relationship_manager from src.chat.message_receive.chat_stream import ChatStream from src.mais4u.mais4u_chat.super_chat_manager import get_super_chat_manager +from src.mais4u.mais4u_chat.screen_manager import screen_manager logger = get_logger("prompt") @@ -30,7 +31,8 @@ def init_prompt(): 虽然是个AI,但你在努力扮演真人, 人设的配色是橙色和紫色和绿色 你有一头法式橙色卷发,你很可爱,穿戴英式侦探风格学院风裙子和帽子,你正在一个教室场景里进行虚拟线上直播。 你可以看见用户发送的弹幕,礼物和superchat -你可以看见面前的屏幕, +你可以看见面前的屏幕,目前屏幕的内容是: +{screen_info} {relation_info_block} {memory_block} @@ -230,6 +232,8 @@ class PromptBuilder: gift_info = self.build_gift_info(message) sc_info = self.build_sc_info(message) + + screen_info = screen_manager.get_screen_str() time_block = f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" @@ -241,6 +245,7 @@ class PromptBuilder: time_block=time_block, relation_info_block=relation_info_block, memory_block=memory_block, + screen_info=screen_info, gift_info=gift_info, sc_info=sc_info, sender_name=sender_name, diff --git a/src/mais4u/mais4u_chat/screen_manager.py b/src/mais4u/mais4u_chat/screen_manager.py new file mode 100644 index 000000000..e937b4f24 --- /dev/null +++ b/src/mais4u/mais4u_chat/screen_manager.py @@ -0,0 +1,14 @@ +class ScreenManager: + def __init__(self): + self.now_screen = str() + + def set_screen(self,screen_str:str): + self.now_screen = screen_str + + def get_screen(self): + return self.now_screen + + def get_screen_str(self): + return f"现在千石可乐在和你一起直播,这是他正在操作的屏幕内容:{self.now_screen}" + +screen_manager = ScreenManager() \ No newline at end of file diff --git a/src/mais4u/mais4u_chat/super_chat_manager.py b/src/mais4u/mais4u_chat/super_chat_manager.py index e2dc96d3d..b5706ca37 100644 --- a/src/mais4u/mais4u_chat/super_chat_manager.py +++ b/src/mais4u/mais4u_chat/super_chat_manager.py @@ -75,7 +75,6 @@ class SuperChatManager: """定期清理过期的SuperChat""" while True: try: - current_time = time.time() total_removed = 0 for chat_id in list(self.super_chats.keys()):