""" 周报生成器 基于需求文档中的周报样式,结合DeepSeek API生成客户群运营与销售工作周报 """ import json import re from datetime import datetime, timedelta from typing import Dict, List, Any, Optional from tools import TimeUtils, DatabaseManager from chat_session import agent class WeeklyReportGenerator: """周报生成器类""" def __init__(self, db_manager: DatabaseManager): self.db = db_manager self.execute_query = self.db.execute_query def get_week_time_range(self, week_str: str) -> tuple: """根据周字符串获取时间范围""" try: # 解析week_str参数,格式为YYYY-WW year, week_num = map(int, week_str.split('-')) # 根据周数计算时间范围 first_day_of_year = datetime(year, 1, 1) # 计算第一周的周一(ISO周从周一开始) first_monday = first_day_of_year + timedelta(days=(7 - first_day_of_year.weekday()) % 7) if first_day_of_year.weekday() <= 3: # 如果1月1日是周一到周四,则属于第一周 first_monday = first_day_of_year - timedelta(days=first_day_of_year.weekday()) # 计算指定周的周一 week_monday = first_monday + timedelta(weeks=week_num - 1) # 计算指定周的周日 week_sunday = week_monday + timedelta(days=6) start_date = week_monday.replace(hour=0, minute=0, second=0, microsecond=0) end_date = week_sunday.replace(hour=23, minute=59, second=59, microsecond=999999) start_timestamp = int(TimeUtils(start_date).to_timestamp()) end_timestamp = int(TimeUtils(end_date).to_timestamp()) return start_timestamp, end_timestamp, start_date, end_date except Exception as e: raise ValueError(f"周次格式错误: {week_str}, 正确格式: YYYY-WW") def get_group_interaction_data(self, start_timestamp: int, end_timestamp: int) -> List[Dict]: """获取各区域群互动数据明细""" query = ''' SELECT g.id, g.name, COUNT(m.id) as message_count, COUNT(DISTINCT m.sender) as active_users FROM "subscribe" g inner JOIN message m ON g.id = m.receiver AND m.time >= ? AND m.time <= ? GROUP BY g.id, g.name ORDER BY message_count DESC ''' result = self.execute_query(query, (f"{start_timestamp}000", f"{end_timestamp}999")) groups_data = [] for row in result: group_data = dict(row) # 获取核心互动时段 peak_hours = self.get_peak_interaction_hours(group_data['id'], start_timestamp, end_timestamp) # 计算平均每日消息量 days_in_week = 7 avg_daily_messages = group_data['message_count'] / days_in_week if days_in_week > 0 else 0 groups_data.append({ 'name': group_data['name'], 'message_count': group_data['message_count'], 'active_users': group_data['active_users'], 'peak_hours': peak_hours, 'avg_daily_messages': round(avg_daily_messages, 1) }) return groups_data def get_peak_interaction_hours(self, group_id: str, start_timestamp: int, end_timestamp: int) -> str: """获取群组的核心互动时段""" query = ''' SELECT strftime('%H', datetime(substr(time, 0, 11), 'unixepoch', '+8 hours')) as hour, COUNT(*) as count FROM message WHERE receiver = ? AND time >= ? AND time <= ? GROUP BY hour ORDER BY count DESC LIMIT 3 ''' result = self.execute_query(query, (group_id, f"{start_timestamp}000", f"{end_timestamp}999")) peak_hours = [] for row in result: hour_data = dict(row) hour = int(hour_data['hour']) peak_hours.append(f"{hour:02d}:00-{hour+1:02d}:00") return ", ".join(peak_hours) if peak_hours else "无数据" def get_hot_topics(self, start_timestamp: int, end_timestamp: int, limit: int = 5) -> List[Dict]: """获取本周热点话题""" # 获取本周消息用于话题分析 query = ''' SELECT content FROM message WHERE time >= ? AND time <= ? AND type IN ('text', 'mixed') ORDER BY time DESC LIMIT ? ''' result = self.execute_query(query, (f"{start_timestamp}000", f"{end_timestamp}999", limit * 10)) messages = [dict(row)['content'] for row in result] # 简单的关键词提取和话题分析 topics = self.analyze_topics(messages, limit) return topics def analyze_topics(self, messages: List[str], limit: int) -> List[Dict]: """分析消息内容,提取热点话题""" # 常见关键词和话题 common_keywords = { '数据对接': ['API接口', '响应速度', '数据格式', '同步', '对接'], '合规申报': ['申报指引', '材料清单', '审核时限', '合规', '申报'], '系统操作': ['操作步骤', '功能使用', '系统填报', '操作指南'], '政策法规': ['政策解读', '法规要求', '法律咨询', '政策变化'], '业务咨询': ['业务操作', '流程咨询', '业务指导', '问题解答'] } topics = [] for topic_name, keywords in common_keywords.items(): frequency = 0 related_groups = set() for message in messages: if any(keyword in message for keyword in keywords): frequency += 1 # 这里可以进一步分析涉及群聊,简化处理 related_groups.add("相关群聊") if frequency > 0: topics.append({ 'name': topic_name, 'keywords': keywords[:3], # 取前3个关键词 'related_groups': list(related_groups)[:2], # 取前2个群聊 'frequency': frequency, 'description': f"客户关注{topic_name}相关问题的讨论" }) # 按频率排序并限制数量 topics.sort(key=lambda x: x['frequency'], reverse=True) return topics[:limit] def get_mapping_messages(self, start_timestamp: int, end_timestamp: int) -> Dict: """获取消息ID到内容的映射""" query = ''' SELECT id, content, time FROM message WHERE time >= ? AND time <= ? ''' result = self.execute_query(query, ( f"{start_timestamp}000", f"{end_timestamp}999")) messages = {} for row in result: message_data = dict(row) messages[message_data['id']] = {'content': message_data['content'], 'timestamp': int(message_data['time'])} return messages def get_customer_issues(self, start_timestamp: int, end_timestamp: int) -> List[Dict]: """获取客户问题汇总与分类""" # 获取QA记录中的问题 query = ''' SELECT q.groupId, q.question, q.answer, g.name as group_name FROM qa q INNER JOIN "subscribe" g ON q.groupId = g.id WHERE q.start_time >= ? AND q.end_time <= ? ORDER BY q.start_time DESC LIMIT 50 ''' result = self.execute_query(query, (f"{start_timestamp}000", f"{end_timestamp}999")) message_mapping = self.get_mapping_messages( start_timestamp=start_timestamp, end_timestamp=end_timestamp) issues = [] for row in result: qa_data = dict(row) try: questions = json.loads(qa_data['question']) answers = json.loads(qa_data['answer']) if questions: # 提取第一个问题作为代表 question_text = [message_mapping.get(qid, {}).get('content', '').replace('\n', '
') for qid in questions] question_text = '
'.join(question_text) # 分类问题 category = self.classify_issue(question_text) issues.append({ 'description': question_text, 'category': category, 'frequency': 1, # 简化处理,每个问题计1次 'group': qa_data.get('group_name', '未知群聊'), 'status': '已回复' if answers and len(answers) > 0 else '提及' }) except: continue return issues def classify_issue(self, question: str) -> str: """分类客户问题""" categories = { '产品使用': ['操作', '功能', '使用', '步骤', '设置'], '服务流程': ['流程', '服务', '响应', 'SLA', '时限'], '需求反馈': ['需求', '建议', '改进', '优化', '增加'], '其他': [] } for category, keywords in categories.items(): if any(keyword in question for keyword in keywords): return category return '其他' def generate_weekly_report(self, week_str: str, use_deepseek: bool = True) -> Dict[str, Any]: """生成周报""" try: # 获取时间范围 start_ts, end_ts, start_date, end_date = self.get_week_time_range(week_str) # 获取基础统计数据 total_messages = self.get_message_count_by_time_range(start_ts, end_ts) total_groups = self.get_group_count() total_active_users = self.get_active_users_by_time_range(start_ts, end_ts) # 获取详细数据 group_interaction_data = self.get_group_interaction_data(start_ts, end_ts) hot_topics = self.get_hot_topics(start_ts, end_ts) customer_issues = self.get_customer_issues(start_ts, end_ts) topic_message_distribution = self.get_topic_message_distribution(start_ts, end_ts) # 生成报告周期字符串 week_period = f"{TimeUtils(start_date).format_custom('%Y年%m月%d日')} - {TimeUtils(end_date).format_custom('%Y年%m月%d日')}" # 构建基础周报内容 report_content = self.build_report_content( week_period=week_period, total_groups=total_groups, total_messages=total_messages, total_active_users=total_active_users, group_interaction_data=group_interaction_data, hot_topics=hot_topics, customer_issues=customer_issues, topic_message_distribution=topic_message_distribution ) # 使用DeepSeek API增强报告内容 if use_deepseek: enhanced_content = self.enhance_with_deepseek(report_content) report_content += "\n" + enhanced_content return { 'success': True, 'report': report_content, 'week': week_str, 'statistics': { 'total_messages': total_messages, 'total_groups': total_groups, 'total_active_users': total_active_users, 'group_interaction_data': group_interaction_data, 'hot_topics': hot_topics, 'customer_issues': customer_issues, 'topic_message_distribution': topic_message_distribution } } except Exception as e: return { 'success': False, 'error': str(e) } def build_report_content(self, **kwargs) -> str: """构建周报内容""" report = f"""# 客户群运营与销售工作周报 周期: {kwargs['week_period']} 生成时间: {datetime.now().strftime('%Y年%m月%d日')} ## 第一部分:客户群聊天记录分析与洞察 ### 1. 互动概况 统计周期: 本周 汇总维度: 覆盖群聊总数: {kwargs['total_groups']} 个 总消息量: {kwargs['total_messages']} 条 总活跃人数: {kwargs['total_active_users']} 人 各区域群互动数据明细(表格): |客户群名称(区域)|消息总量(条)|活跃人数(人)|核心互动时段|平均每日消息量| |---|---|---|---|---| """ # 添加群组数据表格 for group_data in kwargs['group_interaction_data']: report += f"|{group_data['name']}|{group_data['message_count']}|{group_data['active_users']}|{group_data['peak_hours']}|{group_data['avg_daily_messages']}|\n" report += f"""|总计/平均值|{kwargs['total_messages']}|{kwargs['total_active_users']}|-|{round(kwargs['total_messages']/7, 1) if kwargs['total_messages'] > 0 else 0}| ### 2. 本周热点话题 TOP 5 (按讨论频次与参与度综合排序) """ # 添加热点话题 for i, topic in enumerate(kwargs['hot_topics'], 1): report += f""" 话题{i}: {topic['name']} 核心关键词: {', '.join(topic['keywords'])} 涉及主要群聊: {', '.join(topic['related_groups'])} 简要描述: {topic['description']} """ report += f""" ### 3. 客户问题汇总与分类 (分类:产品使用 / 服务流程 / 需求反馈 / 其他) |问题类别|具体问题描述|涉及群聊|当前状态| |---|---|---|---| """ # 添加客户问题 for issue in kwargs['customer_issues']: report += f"|{issue['category']}|{issue['description']}|{issue['group']}|{issue['status']}|\n" report += f""" ### 4. 主题消息发送情况表 (致远速联发送的重复消息分布情况) |消息内容|涉及群|最新发送时间| |---|---|---| """ # 添加主题消息发送情况表 for topic_data in kwargs['topic_message_distribution']: # 只显示前10条 # 截断过长的消息内容 content = topic_data['content'] if len(content) > 50: content = content[:47] + "..." content = content.replace("\n", "
") report += f"|{content}|{topic_data['group']}|{topic_data['time']}|\n" report += f""" ### 5. 需求洞察与行动建议 (基于热点话题与问题提炼的核心需求分析) """ return report def enhance_with_deepseek(self, report_content: str) -> str: """使用DeepSeek API增强报告内容""" try: prompt = """请基于以下周报数据,提供专业的洞察分析和行动建议。 要求: 1. 分析客户需求的核心趋势 2. 提供具体的行动建议 3. 格式要求: 洞察一: [基于热点话题与问题提炼的核心需求] 建议: [可落地的建议] 洞察二: [基于数据分析的发现] 建议: [具体的改进建议] 请用中文回复,保持专业和简洁。""" enhanced_content = agent.chat_deepseek(report_content, prompt) return enhanced_content except Exception as e: return f"\n## AI分析增强\n由于API调用失败,无法提供AI增强分析。错误:{str(e)}" # 辅助方法 - 从现有代码中复制 def get_message_count_by_time_range(self, start_timestamp, end_timestamp): """获取指定时间范围内的消息数量""" result = self.execute_query(''' SELECT COUNT(*) as count FROM message WHERE time >= ? AND time <= ? ''', (f"{start_timestamp}000", f"{end_timestamp}999"), fetch_all=False) return result["count"] def get_active_users_by_time_range(self, start_timestamp, end_timestamp): """获取指定时间范围内的活跃用户数量""" result = self.execute_query(''' SELECT COUNT(DISTINCT sender) as count FROM message WHERE time >= ? AND time <= ? ''', (f"{start_timestamp}000", f"{end_timestamp}999"), fetch_all=False) return result["count"] def get_group_count(self): """获取群组总数""" result = self.execute_query('SELECT COUNT(*) as count FROM "subscribe"', fetch_all=False) return result["count"] def get_topic_message_distribution(self, start_timestamp: int, end_timestamp: int) -> List[Dict]: """获取主题消息发送情况表""" query = ''' SELECT m.content as content, s.name as "group", strftime('%Y-%m-%d %H:%M:%S', datetime(substr(m.time, 0, 11), 'unixepoch', '+8 hours')) as time FROM message as m INNER JOIN ( SELECT m.content, count(1) as count FROM message as m INNER JOIN subscribe as s ON m.receiver = s.id WHERE m.sender = 'ZhiYuanSuLian' AND length(m.content) > 20 AND m.type = 'text' AND m.time >= ? AND m.time <= ? GROUP BY m.content HAVING count(1) > 1 ) as p ON m.content = p.content INNER JOIN subscribe as s ON m.receiver = s.id ORDER BY m.content, time ''' result = self.execute_query(query, (f"{start_timestamp}000", f"{end_timestamp}999")) # 按消息内容分组 topics_list = [] for row in result: row_data = dict(row) topics_list.append(row_data) # 按发送次数降序排序 topics_list.sort(key=lambda x: x['time'], reverse=True) return topics_list