""" 插入模拟面试数据到 Coze 数据库 通过工作流 C1 执行 SQL INSERT 语句 """ import asyncio import httpx import json import random from datetime import datetime, timedelta # Coze 配置 COZE_API_BASE = "https://api.coze.cn" COZE_PAT_TOKEN = "pat_nd1wU47WyPS9GCIyJ1clnH8h1WOQXGrYELX8w73TnSZaYbFdYD4swIhzcETBUbfT" WORKFLOW_ID = "7597376294612107318" # 查询工作流 ID # 模拟候选人数据 MOCK_CANDIDATES = [ {"name": "张小美", "score_base": 85}, {"name": "李明辉", "score_base": 78}, {"name": "王晓丽", "score_base": 92}, {"name": "陈建国", "score_base": 65}, {"name": "刘芳芳", "score_base": 72}, {"name": "赵大伟", "score_base": 58}, {"name": "孙婷婷", "score_base": 88}, {"name": "周志强", "score_base": 45}, ] # 模拟简历内容 MOCK_RESUMES = [ "3年销售经验,曾在某知名医美机构担任销售顾问,业绩连续12个月达成率超过120%。熟悉轻医美产品线,擅长客户关系维护。", "5年美容行业从业经验,持有高级美容师证书。性格开朗,沟通能力强,善于发现客户需求并提供专业建议。", "应届毕业生,市场营销专业,在校期间有丰富的社团活动经验。对医美行业充满热情,学习能力强。", "2年电商销售经验,熟悉线上运营和客户服务。希望转型到线下医美销售领域,有较强的目标感和执行力。", ] # 模拟评估报告模板 SKILL_REPORTS = [ "候选人展现出扎实的销售基础,在产品介绍和需求挖掘方面表现突出。能够灵活运用 FAB 法则,善于建立客户信任。建议加强异议处理技巧的训练。得分:{score}分", "销售技能较为全面,尤其在客户沟通和关系建立方面有独到之处。能够准确把握客户心理,提供针对性的解决方案。需要在成交技巧上进一步打磨。得分:{score}分", "基础销售技能掌握良好,但缺乏实战经验。理论知识扎实,需要更多的实践机会来提升。建议安排老带新的培训模式。得分:{score}分", ] CONCEPT_REPORTS = [ "对销售工作有正确的认知,理解以客户为中心的服务理念。能够平衡业绩压力和客户满意度,具有长期发展的潜力。得分:{score}分", "销售观念较为成熟,认同医美行业的价值观。注重专业性和诚信度,能够为客户提供真诚的建议。得分:{score}分", "对销售工作的理解还停留在表面,需要加强对行业和产品的深入学习。建议多参与案例分析和行业培训。得分:{score}分", ] COMPETENCY_REPORTS = [ "综合素质优秀,具备良好的学习能力和抗压能力。工作态度积极,团队协作意识强。是值得培养的优秀人才。得分:{score}分", "整体素质良好,有较强的责任心和执行力。沟通表达清晰,形象气质佳。建议加强时间管理能力。得分:{score}分", "基本素质合格,但在主动性和自驱力方面有提升空间。需要更多的激励和引导来激发潜力。得分:{score}分", ] MOTIVATION_SUMMARIES = [ "候选人对轻医美行业表现出浓厚的兴趣,希望在这个领域长期发展。主要动机包括:1)看好行业发展前景;2)认同公司品牌价值;3)期待获得专业成长机会。", "求职动机明确,主要是希望获得更好的收入和职业发展平台。对销售工作有热情,愿意接受挑战和压力。", "动机较为单一,主要关注薪资待遇。建议在后续面试中进一步了解其对行业的认知和长期规划。", ] RISK_WARNINGS = [ "", # 无风险 "", # 无风险 "候选人在上一份工作中存在频繁跳槽的情况,需要关注稳定性问题。建议在背调中重点核实离职原因。", "面试过程中发现候选人对公司产品了解不够深入,可能存在准备不充分的情况。建议安排二次面试进一步评估。", "候选人期望薪资与市场水平存在一定差距,需要在 Offer 阶段进行合理沟通。", ] GROWTH_PLANS = [ "建议培养方向:1)前3个月重点学习产品知识和销售流程;2)3-6个月参与实战,由资深顾问带教;3)6个月后独立负责客户。预计1年内可成长为骨干销售。", "该候选人具备快速成长的潜力,建议:1)入职即安排系统培训;2)重点培养其客户开发能力;3)可考虑作为储备管理人才培养。", "成长空间有限,建议先观察3个月试用期表现再做进一步评估。", ] REF_CHECK_LISTS = [ "建议背调问题:\n1. 请确认候选人在贵公司的任职时间和职位\n2. 候选人的主要工作职责是什么?\n3. 您如何评价候选人的销售能力?\n4. 候选人的离职原因是什么?\n5. 如果有机会,您是否愿意再次与其共事?", "重点背调事项:\n1. 核实业绩数据的真实性\n2. 了解团队协作情况\n3. 确认是否有劳动纠纷\n4. 验证学历和证书的真实性", ] # 模拟对话记录 MOCK_DIALOGUES = [ { "stage": "开场", "ai_question": "您好!欢迎参加我们的 AI 面试。我是您的 AI 面试官,接下来我们将进行一次关于销售岗位的面试。首先,请您简单介绍一下自己。", "user_answer": "您好,我叫{name},今年28岁。我有3年的销售工作经验,主要在美容行业从事客户服务和销售工作。我性格开朗,善于与人沟通,对轻医美行业非常感兴趣。" }, { "stage": "销售技能", "ai_question": "很好,感谢您的自我介绍。接下来我想了解一下您的销售经验。请您描述一次成功的销售案例,包括您是如何发现客户需求、如何推荐产品、以及最终如何促成交易的。", "user_answer": "好的。去年我接待了一位40多岁的女士,她最初只是来咨询皮肤保养。通过聊天我发现她其实对法令纹比较在意。我没有直接推销,而是先帮她做了皮肤检测,用数据说明问题。然后根据她的预算和需求,推荐了适合的玻尿酸填充方案。整个过程我注重建立信任,最终她不仅做了法令纹填充,还办了年卡。" }, { "stage": "销售技能", "ai_question": "非常好的案例分享。那么当客户对价格有异议时,您通常如何处理?", "user_answer": "价格异议是很常见的。我通常会先认同客户的感受,然后分析价值而不是价格。比如我会说'您的担心我理解,选择医美确实需要慎重考虑。不过您看,我们使用的是进口正品,由资深医生操作,术后还有专业跟踪服务。很多客户反馈效果能保持1-2年,算下来其实性价比很高。'另外我也会提供分期付款等灵活方案。" }, { "stage": "销售观", "ai_question": "您如何看待销售工作?您认为一个优秀的销售顾问最重要的品质是什么?", "user_answer": "我认为销售的本质是帮助客户解决问题,而不是单纯的推销产品。一个优秀的销售顾问首先要专业,要真正了解产品和客户需求;其次要真诚,不能为了业绩误导客户;最后要有服务意识,把每一位客户都当作长期朋友来维护。" }, { "stage": "素质项", "ai_question": "假设您在工作中遇到了连续三个月业绩不达标的情况,您会如何应对?", "user_answer": "首先我会分析原因,是市场问题、个人方法问题还是其他因素。然后我会主动向业绩好的同事请教,学习他们的成功经验。同时我会调整自己的工作方法,比如增加客户回访频率、优化话术等。最重要的是保持积极心态,相信通过努力一定能改善。" }, { "stage": "求职动机", "ai_question": "最后一个问题,您为什么选择我们公司?您对未来的职业发展有什么规划?", "user_answer": "选择贵公司主要有三个原因:一是贵公司在轻医美领域有很好的口碑和品牌影响力;二是听说公司非常注重员工培训和成长;三是公司的企业文化和我的价值观很匹配。未来我希望能在1-2年内成长为资深销售顾问,3年内有机会带领小团队,为公司创造更大价值。" }, ] async def execute_sql(sql: str, table: str) -> dict: """通过工作流执行 SQL""" headers = { "Authorization": f"Bearer {COZE_PAT_TOKEN}", "Content-Type": "application/json" } payload = { "workflow_id": WORKFLOW_ID, "parameters": { "input": json.dumps({"table": table, "sql": sql}, ensure_ascii=False) } } async with httpx.AsyncClient(timeout=60.0) as client: response = await client.post( f"{COZE_API_BASE}/v1/workflow/run", headers=headers, json=payload ) return response.json() def generate_session_id(name: str, idx: int) -> str: """生成 session_id""" timestamp = datetime.now().strftime("%Y%m%d%H%M") return f"SESS_{timestamp}_{name}_{idx:02d}" def generate_assessment_sql(session_id: str, candidate: dict, idx: int) -> str: """生成评估记录 INSERT SQL""" base = candidate["score_base"] variation = random.randint(-5, 10) skill_score = min(100, max(0, base + random.randint(-8, 8))) concept_score = min(100, max(0, base + random.randint(-5, 10))) competency_score = min(100, max(0, base + random.randint(-10, 5))) skill_report = random.choice(SKILL_REPORTS).format(score=skill_score) concept_report = random.choice(CONCEPT_REPORTS).format(score=concept_score) competency_report = random.choice(COMPETENCY_REPORTS).format(score=competency_score) motivation = random.choice(MOTIVATION_SUMMARIES) risk = random.choice(RISK_WARNINGS) growth = random.choice(GROWTH_PLANS) ref_check = random.choice(REF_CHECK_LISTS) resume = random.choice(MOCK_RESUMES) # 转义单引号 def escape(s): return s.replace("'", "''") if s else "" sql = f"""INSERT INTO ci_interview_assessments ( session_id, candidate_name, current_stage, sales_skill_score, sales_skill_report, sales_concept_score, sales_concept_report, competency_score, competency_report, motivation_summary, risk_warning, growth_plan, ref_check_list, resume_text ) VALUES ( '{session_id}', '{candidate["name"]}', '10', '{skill_score}', '{escape(skill_report)}', '{concept_score}', '{escape(concept_report)}', '{competency_score}', '{escape(competency_report)}', '{escape(motivation)}', '{escape(risk)}', '{escape(growth)}', '{escape(ref_check)}', '{escape(resume)}' )""" return sql def generate_log_sql(session_id: str, candidate_name: str, round_num: int, dialogue: dict, idx: int) -> str: """生成对话记录 INSERT SQL""" import uuid def escape(s): return s.replace("'", "''").replace("{name}", candidate_name) if s else "" # 生成唯一的 log_id log_id = f"LOG_{idx:02d}_{round_num:02d}_{uuid.uuid4().hex[:8]}" sql = f"""INSERT INTO ci_interview_logs ( log_id, session_id, stage, round, ai_question, user_answer, log_type ) VALUES ( '{log_id}', '{session_id}', '{dialogue["stage"]}', '{round_num}', '{escape(dialogue["ai_question"])}', '{escape(dialogue["user_answer"])}', 'interview' )""" return sql async def main(): print("=" * 60) print("开始插入模拟面试数据...") print("=" * 60) success_count = 0 error_count = 0 for idx, candidate in enumerate(MOCK_CANDIDATES): session_id = generate_session_id(candidate["name"], idx) print(f"\n[{idx + 1}/{len(MOCK_CANDIDATES)}] 处理候选人: {candidate['name']}") print(f" Session ID: {session_id}") # 1. 插入评估记录 try: assessment_sql = generate_assessment_sql(session_id, candidate, idx) print(f" 插入评估记录...") result = await execute_sql(assessment_sql, "assessments") if result.get("code") == 0: print(f" ✓ 评估记录插入成功") success_count += 1 else: print(f" ✗ 评估记录插入失败: {result}") error_count += 1 except Exception as e: print(f" ✗ 评估记录插入异常: {e}") error_count += 1 # 2. 插入对话记录 for round_num, dialogue in enumerate(MOCK_DIALOGUES, 1): try: log_sql = generate_log_sql(session_id, candidate["name"], round_num, dialogue, idx) print(f" 插入对话记录 (第{round_num}轮)...") result = await execute_sql(log_sql, "logs") if result.get("code") == 0: print(f" ✓ 对话记录 {round_num} 插入成功") success_count += 1 else: print(f" ✗ 对话记录 {round_num} 插入失败: {result}") error_count += 1 except Exception as e: print(f" ✗ 对话记录 {round_num} 插入异常: {e}") error_count += 1 # 等待一下避免请求过快 await asyncio.sleep(1) print("\n" + "=" * 60) print(f"数据插入完成!") print(f"成功: {success_count} 条") print(f"失败: {error_count} 条") print("=" * 60) if __name__ == "__main__": asyncio.run(main())