#!/usr/bin/env python """ 为统计分析页面生成轻医美场景的模拟数据 生成的数据包括: 1. 考试记录(exams)- 不同时间段、不同课程、不同分数 2. 错题记录(exam_mistakes)- 不同难度、不同知识点 3. 陪练会话(practice_sessions)- 不同时间的陪练记录 4. 知识点数据(knowledge_points)- 轻医美相关知识点 目标:确保统计分析页面的每个模块都能显示数据 """ import sys import asyncio from datetime import datetime, timedelta import random from pathlib import Path # 添加项目路径 project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from sqlalchemy import select, func from app.models.exam import Exam, Question from app.models.exam_mistake import ExamMistake from app.models.course import Course, KnowledgePoint from app.models.practice import PracticeSession from app.models.user import User from app.core.logger import get_logger logger = get_logger(__name__) # 数据库连接(开发测试环境) DATABASE_URL = "mysql+aiomysql://root:nj861021@localhost:3306/kaopeilian" # 轻医美知识点数据 BEAUTY_KNOWLEDGE_POINTS = { "皮肤生理学基础": [ "皮肤结构与层次", "皮肤类型与特征", "皮肤屏障功能", "皮肤老化机制", "皮肤色素形成", "皮肤水分平衡" ], "医美产品知识与应用": [ "透明质酸的应用", "肉毒素的作用机理", "光子嫩肤原理", "果酸焕肤技术", "维生素C美白", "胶原蛋白补充" ], "美容仪器操作与维护": [ "超声刀操作流程", "热玛吉治疗参数", "皮秒激光使用", "射频美容仪器", "冷光美肤仪", "水光注射仪" ], "轻医美销售技巧": [ "客户需求分析", "项目推荐话术", "价格异议处理", "成交技巧", "客户关系维护", "套餐设计方法" ], "客户服务与投诉处理": [ "服务标准流程", "投诉应对技巧", "客户期望管理", "售后跟踪服务", "客户满意度提升", "危机公关处理" ] } # 难度级别 DIFFICULTY_LEVELS = ["easy", "medium", "hard"] async def clear_old_demo_data(db: AsyncSession, user_id: int): """清理旧的演示数据""" logger.info(f"清理用户 {user_id} 的旧演示数据...") # 清理考试记录(会级联删除错题记录) from sqlalchemy import delete await db.execute(delete(Exam).where(Exam.user_id == user_id)) # 清理陪练会话 await db.execute(delete(PracticeSession).where(PracticeSession.user_id == user_id)) await db.commit() logger.info("旧数据清理完成") async def get_or_create_knowledge_points(db: AsyncSession, course_id: int, course_name: str) -> list: """获取或创建知识点""" # 检查是否已有知识点 result = await db.execute( select(KnowledgePoint).where( KnowledgePoint.course_id == course_id, KnowledgePoint.is_deleted == False ) ) existing_kps = result.scalars().all() if existing_kps: logger.info(f"课程 {course_name} 已有 {len(existing_kps)} 个知识点") return existing_kps # 创建新知识点 knowledge_points = [] if course_name in BEAUTY_KNOWLEDGE_POINTS: for kp_name in BEAUTY_KNOWLEDGE_POINTS[course_name]: kp = KnowledgePoint( course_id=course_id, name=kp_name, description=f"{course_name}中的重要知识点:{kp_name}", type="核心概念", source=0, # 手动创建 is_deleted=False ) db.add(kp) knowledge_points.append(kp) await db.commit() # 刷新以获取ID for kp in knowledge_points: await db.refresh(kp) logger.info(f"为课程 {course_name} 创建了 {len(knowledge_points)} 个知识点") return knowledge_points async def create_exam_records(db: AsyncSession, user_id: int, courses: list): """创建考试记录""" logger.info("创建考试记录...") end_date = datetime.now() exams_created = 0 # 在过去60天内创建考试记录 for days_ago in range(60, 0, -1): exam_date = end_date - timedelta(days=days_ago) # 跳过一些日期(不是每天都考试) if random.random() > 0.3: # 30%的日子有考试 continue # 每天可能考1-2次 num_exams = random.choice([1, 1, 1, 2]) for _ in range(num_exams): # 随机选择课程 course = random.choice(courses) # 生成考试分数(呈现进步趋势) # 早期分数较低,后期分数较高 progress_factor = (60 - days_ago) / 60 # 0 到 1 base_score = 60 + (progress_factor * 20) # 60-80分基础 score_variance = random.uniform(-10, 15) round1_score = max(50, min(100, base_score + score_variance)) # 创建考试记录 exam = Exam( user_id=user_id, course_id=course.id, exam_name=f"{course.name}测试", question_count=10, total_score=100.0, pass_score=60.0, start_time=exam_date, end_time=exam_date + timedelta(minutes=random.randint(15, 45)), duration_minutes=random.randint(15, 45), round1_score=round(round1_score, 1), round2_score=None, round3_score=None, score=round(round1_score, 1), is_passed=round1_score >= 60, status="submitted" ) db.add(exam) exams_created += 1 await db.commit() logger.info(f"创建了 {exams_created} 条考试记录") return exams_created async def create_exam_mistakes(db: AsyncSession, user_id: int, courses: list): """创建错题记录""" logger.info("创建错题记录...") # 获取用户的所有考试 result = await db.execute( select(Exam).where(Exam.user_id == user_id).order_by(Exam.start_time) ) exams = result.scalars().all() mistakes_created = 0 for exam in exams: # 找到对应的课程 course = next((c for c in courses if c.id == exam.course_id), None) if not course: continue # 获取该课程的知识点 result = await db.execute( select(KnowledgePoint).where( KnowledgePoint.course_id == course.id, KnowledgePoint.is_deleted == False ) ) knowledge_points = result.scalars().all() if not knowledge_points: continue # 根据分数决定错题数(分数越低,错题越多) score = exam.round1_score or 70 mistake_rate = (100 - score) / 100 # 0.0 到 0.5 num_mistakes = int(exam.question_count * mistake_rate) num_mistakes = max(1, min(num_mistakes, exam.question_count - 1)) # 创建错题 for i in range(num_mistakes): # 随机选择知识点 kp = random.choice(knowledge_points) # 随机选择题型 question_types = ["single_choice", "multiple_choice", "true_false", "fill_blank", "essay"] question_type = random.choice(question_types) mistake = ExamMistake( user_id=user_id, exam_id=exam.id, question_id=None, # AI生成的题目 knowledge_point_id=kp.id, question_content=f"关于{kp.name}的问题{i+1}", correct_answer="正确答案", user_answer="用户错误答案", question_type=question_type ) db.add(mistake) mistakes_created += 1 await db.commit() logger.info(f"创建了 {mistakes_created} 条错题记录") return mistakes_created async def create_practice_sessions(db: AsyncSession, user_id: int): """创建陪练会话记录""" logger.info("创建陪练会话记录...") end_date = datetime.now() sessions_created = 0 # 在过去60天内创建陪练记录 for days_ago in range(60, 0, -1): session_date = end_date - timedelta(days=days_ago) # 跳过一些日期 if random.random() > 0.25: # 25%的日子有陪练 continue # 每次陪练的时长(秒) duration_seconds = random.randint(600, 1800) # 10-30分钟 # 场景类型 scene_types = ["电话销售", "面对面咨询", "客户投诉处理", "售后服务", "产品介绍"] scene_name = random.choice(scene_types) session = PracticeSession( session_id=f"session_{user_id}_{int(session_date.timestamp())}", user_id=user_id, scene_id=random.randint(1, 5), scene_name=scene_name, scene_type=scene_name, start_time=session_date, end_time=session_date + timedelta(seconds=duration_seconds), duration_seconds=duration_seconds, turns=random.randint(10, 30), status="completed", is_deleted=False ) db.add(session) sessions_created += 1 await db.commit() logger.info(f"创建了 {sessions_created} 条陪练会话记录") return sessions_created async def main(): """主函数""" logger.info("=" * 60) logger.info("开始为统计分析页面生成轻医美场景的模拟数据") logger.info("=" * 60) # 创建数据库连接 engine = create_async_engine(DATABASE_URL, echo=False) async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) try: async with async_session() as db: # 1. 获取测试用户(admin或第一个用户) result = await db.execute( select(User).where(User.username == "admin") ) user = result.scalar_one_or_none() if not user: # 如果没有admin,使用第一个用户 result = await db.execute(select(User).limit(1)) user = result.scalar_one_or_none() if not user: logger.error("❌ 未找到用户,请先创建用户") return logger.info(f"📝 使用用户: {user.username} (ID: {user.id})") # 2. 获取轻医美相关课程 result = await db.execute( select(Course).where( Course.is_deleted == False, Course.status == "published" ) ) courses = result.scalars().all() if not courses: logger.error("❌ 未找到已发布的课程") return logger.info(f"📚 找到 {len(courses)} 门课程") # 3. 清理旧数据(可选) clear_old = input("\n是否清理该用户的旧数据?(y/n): ").lower() if clear_old == 'y': await clear_old_demo_data(db, user.id) # 4. 为每门课程创建知识点 logger.info("\n" + "=" * 60) logger.info("步骤 1/3: 创建知识点") logger.info("=" * 60) for course in courses: await get_or_create_knowledge_points(db, course.id, course.name) # 5. 创建考试记录 logger.info("\n" + "=" * 60) logger.info("步骤 2/3: 创建考试记录") logger.info("=" * 60) exams_count = await create_exam_records(db, user.id, courses) # 6. 创建错题记录 logger.info("\n" + "=" * 60) logger.info("步骤 3/3: 创建错题记录") logger.info("=" * 60) mistakes_count = await create_exam_mistakes(db, user.id, courses) # 7. 创建陪练会话记录 logger.info("\n" + "=" * 60) logger.info("步骤 4/4: 创建陪练会话记录") logger.info("=" * 60) sessions_count = await create_practice_sessions(db, user.id) # 8. 统计信息 logger.info("\n" + "=" * 60) logger.info("✅ 数据生成完成!") logger.info("=" * 60) logger.info(f"用户: {user.username} (ID: {user.id})") logger.info(f"考试记录: {exams_count} 条") logger.info(f"错题记录: {mistakes_count} 条") logger.info(f"陪练记录: {sessions_count} 条") logger.info("=" * 60) logger.info("\n现在可以访问统计分析页面查看数据:") logger.info("http://localhost:5173/analysis/statistics") logger.info("=" * 60) except Exception as e: logger.error(f"❌ 生成数据失败: {e}") import traceback traceback.print_exc() finally: await engine.dispose() if __name__ == "__main__": asyncio.run(main())