from collections import defaultdict import requests import json from app.models import RequirementAnalysis, TestCaseResult, CodeGenerationResult webhook_url = "https://open.feishu.cn/open-apis/bot/v2/hook/0cd37406-31b8-424a-a3da-c11ce465ac29" def send_message_to_feishu(message: str): data = { "msg_type": "text", "content": { "text": message } } requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(data) ) def send_requirement_result(requirement_analysis: RequirementAnalysis): data = { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿ“Œ ้œ€ๆฑ‚ๅˆ†ๆž็ป“ๆžœ" }, "template": "blue" }, "elements": [ { "tag": "markdown", "content": f"---\n**๐Ÿ“Ž ๆ€ป็ป“๏ผš**\n\n{requirement_analysis['summary']}" }, { "tag": "markdown", "content": f"### ๐Ÿงฉ ๅŠŸ่ƒฝ้œ€ๆฑ‚\n\n{chr(10).join([f'- {req}' for req in requirement_analysis['functional_requirements']])}" }, { "tag": "markdown", "content": f"### ๐Ÿš€ ้žๅŠŸ่ƒฝ้œ€ๆฑ‚\n\n{chr(10).join([f'- {req}' for req in requirement_analysis['non_functional_requirements']])}" }, { "tag": "markdown", "content": f"### โš ๏ธ ่พน็•Œๆƒ…ๅ†ต\n\n{chr(10).join([f'- {case}' for case in requirement_analysis['edge_cases']])}" }, { "tag": "markdown", "content": f"### โœ… ้ชŒๆ”ถๆ ‡ๅ‡†\n\n{chr(10).join([f'- {criteria}' for criteria in requirement_analysis['acceptance_criteria']])}" } ] } } requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(data) ) def send_generate_code(code_result: CodeGenerationResult): implementation_notes_data = { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿ“Œ ไปฃ็ ็”Ÿๆˆ็ป“ๆžœ - ๅฎž็Žฐๆ€่ทฏ" }, "template": "green" }, "elements": [ { "tag": "markdown", "content": code_result['implementation_notes'] } ] } } java_code_data = { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿ“Œ ไปฃ็ ็”Ÿๆˆ็ป“ๆžœ - ไธšๅŠกไปฃ็ " }, "template": "green" }, "elements": [ { "tag": "markdown", "content": code_result['java_code'] } ] } } unit_tests_data = { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿš€ ไปฃ็ ็”Ÿๆˆ็ป“ๆžœ - ๆต‹่ฏ•ไปฃ็ " }, "template": "green" }, "elements": [ { "tag": "markdown", "content": code_result['unit_tests'] } ] } } passed_tests_data = { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿš€ ไปฃ็ ็”Ÿๆˆ็ป“ๆžœ - ๅ•ๅ…ƒๆต‹่ฏ•ๆ‰ง่กŒ็ป“ๆžœ" }, "template": "green" }, "elements": [ { "tag": "markdown", "content": f""" ### ๐Ÿ“Š ๆต‹่ฏ•็ปŸ่ฎก - **ๆ€ป็”จไพ‹ๆ•ฐ๏ผš** {code_result['unit_tests_count']} - **้€š่ฟ‡๏ผš** {code_result['passed_tests_count']} """ } ] } } requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(implementation_notes_data) ) requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(java_code_data) ) requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(unit_tests_data) ) requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(passed_tests_data) ) def send_test_cases(test_case: TestCaseResult): requests.post( webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(build_full_feishu_card(test_case)) ) def build_full_feishu_card(data: TestCaseResult) -> dict: test_cases = data.get("test_cases", []) type_counter = defaultdict(int) grouped_cases = defaultdict(list) # ๅˆ†็ป„ + ็ปŸ่ฎก for case in test_cases: t_type = case.get("test_type", "ๆœชๅˆ†็ฑป") type_counter[t_type] += 1 grouped_cases[t_type].append(case) total = len(test_cases) elements = [] # ๐Ÿ“Š ็ปŸ่ฎก stats_text = "### ๐Ÿ“Š ๆต‹่ฏ•็ปŸ่ฎก\n\n" stats_text += f"- ๆ€ป็”จไพ‹ๆ•ฐ๏ผš**{total}**\n" for k, v in type_counter.items(): stats_text += f"- {k}๏ผš{v}\n" elements.append({ "tag": "markdown", "content": stats_text }) # ๐Ÿ—‚ ๅˆ†็ป„ + ๅ…จ้‡ๅฑ•็คบ for test_type, cases in grouped_cases.items(): elements.append({ "tag": "markdown", "content": f"---\n## ๐Ÿ—‚ {test_type}" }) for case in cases: steps_text = "\n".join([f" {i+1}. {s}" for i, s in enumerate(case.get("steps", []))]) case_text = f"""### {case.get('test_id')} - {case.get('test_name')} - **ๅ‰็ฝฎๆกไปถ๏ผš** {case.get('precondition')} - **ๆ‰ง่กŒๆญฅ้ชค๏ผš** {steps_text} - **ๆœŸๆœ›็ป“ๆžœ๏ผš** {case.get('expected_result')} """ elements.append({ "tag": "markdown", "content": case_text }) # ๐Ÿง  ๆต‹่ฏ•็ญ–็•ฅ elements.append({ "tag": "markdown", "content": f"---\n### ๐Ÿง  ๆต‹่ฏ•็ญ–็•ฅ\n\n{data.get('test_strategy')}" }) # ๐ŸŽฏ ่ฆ†็›–่ฎกๅˆ’ elements.append({ "tag": "markdown", "content": f"---\n### ๐ŸŽฏ ่ฆ†็›–่ฎกๅˆ’\n\n{data.get('coverage_plan')}" }) return { "msg_type": "interactive", "card": { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "๐Ÿงช ่‡ชๅŠจๅŒ–ๆต‹่ฏ•็”จไพ‹็ป“ๆžœ" }, "template": "blue" }, "elements": elements } }