Files

1 line
40 KiB
JSON

{"repo": "13429837441/autogentestcase", "files": {"llms.py": {"917266b4b54ce26cae3938eff6a8357344c2dddc": {"t": 1785674053.277481, "n": 2120, "h": "299fd3838c7d02d2", "c": "#!/usr/bin/python\r\n# -*- coding: utf-8 -*-\r\n\r\nmodel_deepseek_info = {\r\n \"name\": \"deepseek-chat\", # 模型名称,可随意填写\r\n \"parameters\": {\r\n \"max_tokens\": 2048, # 每次输出最大token数\r\n # deepseek官方数据:1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token。\r\n \"temperature\": 0.4, # 模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,\r\n # 如果希望AI提供更多的想法,可以调大该数字\r\n \"top_p\": 0.9, # 模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\r\n # 接近 0 时:只有概率非常高的极少数词会被考虑,这会使模型的输出变得非常保守和确定\r\n },\r\n \"family\": \"gpt-4o\", # 必填字段,model属于的类别\r\n \"functions\": [], # 非必填字段,如果模型支持函数调用,可以在这里定义函数信息\r\n \"vision\": False, # 必填字段,模型是否支持图像输入\r\n \"json_output\": True, # 必填字段,模型是否支持json格式输出\r\n \"function_calling\": True, # 必填字段,模型是否支持函数调用,如果模型需要使用工具函数,该字段为true\r\n \"structured_output\": True # 结构化输出\r\n }\r\n\r\n# model_deepseek_client = OpenAIChatCompletionClient(\r\n# model=\"deepseek-chat\",\r\n# base_url=\"https://api.deepseek.com\",\r\n# api_key=\"sk-79f54a8dcf024fb8bcf3d13ada930a7e\",\r\n# model_info=model_deepseek_info,\r\n# )\r\n\r\nmodel_qwen_info = {\r\n \"name\": \"qwen-chat\", # 模型名称,可随意填写\r\n \"parameters\": {\r\n \"max_tokens\": 4096, # 每次输出最大token数\r\n # deepseek官方数据:1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token。\r\n \"temperature\": 0.7, # 模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,\r\n # 如果希望AI提供更多的想法,可以调大该数字\r\n \"top_p\": 0.8, # 模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\r\n # 接近 0 时:只有概率非常高的极少数词会被考虑,这会使模型的输出变得非常保守和确定\r\n },\r\n \"family\": \"gpt-4o\", # 必填字段,model属于的类别\r\n \"functions\": [], # 非必填字段,如果模型支持函数调用,可以在这里定义函数信息\r\n \"vision\": False, # 必填字段,模型是否支持图像输入\r\n \"json_output\": True, # 必填字段,模型是否支持json格式输出\r\n \"function_calling\": True, # 必填字段,模型是否支持函数调用,如果模型需要使用工具函数,该字段为true\r\n \"structured_output\": True # 结构化输出\r\n }\r\n\r\n# model_qwen_client = OpenAIChatCompletionClient(\r\n# model=\"qwen-max\",\r\n# base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\r\n# api_key=\"sk-73f2726c462b4933bc85a5649d2d081f\",\r\n# model_info=model_qwen_info,\r\n# )\r\n"}, "351db68810c0a825e2e7a3952bdba04f4c08aa0d": {"t": 1785773552.0636477, "n": 2120, "h": "299fd3838c7d02d2", "c": "#!/usr/bin/python\r\n# -*- coding: utf-8 -*-\r\n\r\nmodel_deepseek_info = {\r\n \"name\": \"deepseek-chat\", # 模型名称,可随意填写\r\n \"parameters\": {\r\n \"max_tokens\": 2048, # 每次输出最大token数\r\n # deepseek官方数据:1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token。\r\n \"temperature\": 0.4, # 模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,\r\n # 如果希望AI提供更多的想法,可以调大该数字\r\n \"top_p\": 0.9, # 模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\r\n # 接近 0 时:只有概率非常高的极少数词会被考虑,这会使模型的输出变得非常保守和确定\r\n },\r\n \"family\": \"gpt-4o\", # 必填字段,model属于的类别\r\n \"functions\": [], # 非必填字段,如果模型支持函数调用,可以在这里定义函数信息\r\n \"vision\": False, # 必填字段,模型是否支持图像输入\r\n \"json_output\": True, # 必填字段,模型是否支持json格式输出\r\n \"function_calling\": True, # 必填字段,模型是否支持函数调用,如果模型需要使用工具函数,该字段为true\r\n \"structured_output\": True # 结构化输出\r\n }\r\n\r\n# model_deepseek_client = OpenAIChatCompletionClient(\r\n# model=\"deepseek-chat\",\r\n# base_url=\"https://api.deepseek.com\",\r\n# api_key=\"sk-79f54a8dcf024fb8bcf3d13ada930a7e\",\r\n# model_info=model_deepseek_info,\r\n# )\r\n\r\nmodel_qwen_info = {\r\n \"name\": \"qwen-chat\", # 模型名称,可随意填写\r\n \"parameters\": {\r\n \"max_tokens\": 4096, # 每次输出最大token数\r\n # deepseek官方数据:1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token。\r\n \"temperature\": 0.7, # 模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,\r\n # 如果希望AI提供更多的想法,可以调大该数字\r\n \"top_p\": 0.8, # 模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\r\n # 接近 0 时:只有概率非常高的极少数词会被考虑,这会使模型的输出变得非常保守和确定\r\n },\r\n \"family\": \"gpt-4o\", # 必填字段,model属于的类别\r\n \"functions\": [], # 非必填字段,如果模型支持函数调用,可以在这里定义函数信息\r\n \"vision\": False, # 必填字段,模型是否支持图像输入\r\n \"json_output\": True, # 必填字段,模型是否支持json格式输出\r\n \"function_calling\": True, # 必填字段,模型是否支持函数调用,如果模型需要使用工具函数,该字段为true\r\n \"structured_output\": True # 结构化输出\r\n }\r\n\r\n# model_qwen_client = OpenAIChatCompletionClient(\r\n# model=\"qwen-max\",\r\n# base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\r\n# api_key=\"sk-73f2726c462b4933bc85a5649d2d081f\",\r\n# model_info=model_qwen_info,\r\n# )\r\n"}}, "page.py": {"917266b4b54ce26cae3938eff6a8357344c2dddc": {"t": 1785674056.015297, "n": 29316, "h": "ba7e2e38af2d2a21", "c": "#!/usr/bin/python\r\n# -*- coding: utf-8 -*-\r\nfrom autogen_ext.models.openai import OpenAIChatCompletionClient\r\nfrom autogen_agentchat.conditions import TextMentionTermination\r\nfrom autogen_agentchat.teams import RoundRobinGroupChat\r\nfrom autogen_agentchat.agents import AssistantAgent\r\nimport streamlit.components.v1 as components\r\nfrom configparser import ConfigParser\r\nfrom pathlib import Path\r\nimport streamlit as st\r\nfrom io import BytesIO\r\nfrom llms import *\r\nimport xlsxwriter\r\nimport platform\r\nimport asyncio\r\nimport base64\r\nimport time\r\nimport os\r\nimport re\r\n\r\n# 设置页面配置\r\nst.set_page_config(\r\n page_title=\"测试用例生成辅助工具\",\r\n page_icon=\":tm:\",\r\n layout=\"wide\"\r\n)\r\n\r\nconf = ConfigParser()\r\npt = platform.system()\r\nmain_path = os.path.split(os.path.realpath(__file__))[0]\r\nconfig_path = os.path.join(os.path.split(os.path.realpath(__file__))[0], 'config.ini')\r\n\r\n\r\ndef css_init():\r\n st.markdown('''<style>\r\n.edw49t12 {\r\n max-width: 500px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n</style>''', unsafe_allow_html=True)\r\n\r\n\r\ndef session_init():\r\n if 'run_cases' not in st.session_state:\r\n st.session_state.run_cases = True\r\n\r\n\r\ndef main():\r\n if pt in [\"Windows\"]:\r\n session_init() # session缓存初始化\r\n css_init() # 前端css样式初始化\r\n html_init() # 前端html布局初始化\r\n else:\r\n cs_404()\r\n return None\r\n\r\n\r\ndef cs_404():\r\n # 背景图片的网址\r\n img_url = 'https://img.zcool.cn/community/0156cb59439764a8012193a324fdaa.gif'\r\n\r\n # 修改背景样式\r\n st.markdown('''<span style=\"color: cyan\"> ''' + f\"不支持当前系统 {pt} 运行\" + '''</span>''', unsafe_allow_html=True)\r\n st.markdown('''<style>.css-fg4pbf{background-image:url(''' + img_url + ''');\r\n background-size:100% 100%;background-attachment:fixed;}</style>''', unsafe_allow_html=True)\r\n\r\n\r\ndef img_to_bytes(img_path):\r\n img_bytes = Path(os.path.split(os.path.realpath(__file__))[0] + \"\\\\\" + img_path).read_bytes()\r\n encoded = base64.b64encode(img_bytes).decode()\r\n return encoded\r\n\r\n\r\ndef read_system_message(filename):\r\n message_path = os.path.join(main_path, filename)\r\n with open(message_path, \"r\", encoding=\"utf8\") as f: # 打开文件\r\n data = f.read() # 读取文件\r\n return data\r\n\r\n\r\n# 创建测试用例生成器代理\r\n@st.cache_resource\r\ndef get_testcase_writer(_mode_client, system_message):\r\n return AssistantAgent(\r\n name=\"testcase_writer\",\r\n model_client=_mode_client,\r\n system_message=system_message,\r\n # model_client_stream=True,\r\n )\r\n\r\n\r\n# 创建评审用例生成器代理\r\n@st.cache_resource\r\ndef get_testcase_reader(_mode_client, system_message):\r\n return AssistantAgent(\r\n name=\"critic\",\r\n model_client=_mode_client,\r\n system_message=system_message,\r\n model_client_stream=True,\r\n )\r\n\r\n\r\n# 用例格式化\r\n@st.cache_resource\r\ndef format_testcases(raw_output):\r\n cases = re.findall(r'(\\|.+\\|)', raw_output, re.IGNORECASE)\r\n new_cases = list(dict.fromkeys(cases))\r\n return new_cases\r\n\r\n\r\ndef html_init():\r\n js_code = '''\r\n $(document).ready(function(){\r\n $(\"footer\", window.parent.document).remove()\r\n });\r\n '''\r\n # 引用了JQuery v2.2.4\r\n components.html(f'''<script src=\"https://cdn.bootcdn.net/ajax/libs/jquery/2.2.4/jquery.min.js\"></script>\r\n <script>{js_code}</script>''', width=0, height=0)\r\n # sidebar图标\r\n st.sidebar.markdown(\r\n '''<a href=\"#\"><img src='data:image/png;base64,{}' class='img-fluid' width=40 height=40 target='_self'></a>'''.format(\r\n img_to_bytes(\"img/Jack.png\")), unsafe_allow_html=True)\r\n\r\n # sidebar.expander\r\n with st.sidebar:\r\n expander1 = st.expander(\"使用说明\", True)\r\n with expander1:\r\n st.markdown(\r\n \"\"\"\r\n 👉<a href=\"https://github.com/13429837441/AutoGenTestCase/blob/main/README.md\" target='blank'>模型ApiKey申请说明</a>👈\r\n ### **使用步骤**\r\n ##### 1、上传文件(.txt)或手动输入需求描述\r\n ##### 2、设置高级选项设置\r\n ##### 3、点击\"生成测试用例\"按钮\r\n ##### 4、查看生成的测试用例\r\n ##### 5、下载测试用例文件\r\n \r\n ### **高级选项设置**\r\n ##### **用例分类**:选择用例类型(功能验证用例、边界用例、异常场景用例、性能/兼容性用例、回归测试用例)\r\n ##### **用例优先级**:设置整体用例的优先级\r\n \"\"\"\r\n , unsafe_allow_html=True)\r\n\r\n expander2 = st.expander(\"关于\", False)\r\n with expander2:\r\n st.markdown(\r\n \"\"\"\r\n ###### 本工具使用到的AI工具包括(DeepSeek、通义千问)\r\n ###### AI工具生成的测试用例可作为参考使用,具体业务还需要人工干预并进行补充\r\n ###### 本工具是利用deepseek写测试用例,通义千问负责用例评审\r\n \"\"\"\r\n )\r\n # sidebar标题\r\n st.sidebar.markdown(\"---\")\r\n\r\n st.sidebar.markdown('''<small style='float: right'>By <a id=\"reload\" href=\"#公众号:One Little Testing\" title=\"公众号:One Little Testing\">@Jack</a></small>''',\r\n unsafe_allow_html=True)\r\n\r\n # 读取配置\r\n conf.read(config_path)\r\n deep_base_url_list = conf['deepseek']['base_url_list'].split(\",\")\r\n qwen_base_url_list = conf['qwen']['base_url_list'].split(\",\")\r\n deep_model_list = conf['deepseek']['model_list'].split(\",\")\r\n qwen_model_list = conf['qwen']['model_list'].split(\",\")\r\n # main主页面\r\n source_tab1, source_tab2 = st.tabs([\"⚙AI模型设置\", \"🖥 AI交互\"])\r\n # AI模型设置\r\n with source_tab1:\r\n st.subheader(\"DeepSeek模型配置【单角色:编写用例】\")\r\n ai1 = st.checkbox(\"deepseek\", eval(conf['deepseek']['choice']))\r\n cols1 = st.columns([2, 2, 2])\r\n if ai1:\r\n api_key_1 = cols1[0].text_input(\"deepseek_api_key\",\r\n placeholder=\"sk-xxxxxxxxxxxxx\",\r\n value=conf['deepseek']['api_key'])\r\n base_url_1 = cols1[1].selectbox(\"base_url\", deep_base_url_list[:-1],\r\n index=deep_base_url_list.index(conf['deepseek']['base_url']))\r\n model_1 = cols1[2].selectbox(\"model\", deep_model_list[:-1],\r\n index=deep_model_list.index(conf['deepseek']['model']))\r\n max_tokens_1 = cols1[0].number_input(\"Deep最大输出Token:\",\r\n max_value=4096,\r\n min_value=0,\r\n value=int(conf['deepseek']['tokens']),\r\n help=\"1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token\")\r\n temperature_1 = cols1[1].number_input(\"Deep模型随机性参数temperature:\",\r\n max_value=20,\r\n min_value=0,\r\n value=int(conf['deepseek']['temperature']),\r\n help=\"模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,如果希望AI提供更多的想法,可以调大该数字\")\r\n top_p_1 = cols1[2].number_input(\"Deep模型随机性参数top:\",\r\n max_value=10,\r\n min_value=0,\r\n value=int(conf['deepseek']['top']),\r\n help=\"模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\")\r\n\r\n st.subheader(\"通义千问模型配置【多角色:评审用例】\")\r\n ai2 = st.checkbox(\"Qwen\", eval(conf['qwen']['choice']))\r\n cols2 = st.columns([2, 2, 2])\r\n if ai2:\r\n api_key_2 = cols2[0].text_input(\"qwen_api_key\",\r\n placeholder=\"sk-xxxxxxxxxxxxx\",\r\n value=conf['qwen']['api_key'])\r\n base_url_2 = cols2[1].selectbox(\"base_url\", qwen_base_url_list[:-1],\r\n index=qwen_base_url_list.index(conf['qwen']['base_url']))\r\n model_2 = cols2[2].selectbox(\"model\", qwen_model_list[:-1],\r\n index=qwen_model_list.index(conf['qwen']['model']))\r\n max_tokens_2 = cols2[0].number_input(\"Qwen最大输出Token:\",\r\n max_value=4096,\r\n min_value=0,\r\n value=int(conf['qwen']['tokens']),\r\n help=\"1个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token\")\r\n temperature_2 = cols2[1].number_input(\"Qwen模型随机性参数temperature:\",\r\n max_value=20,\r\n min_value=0,\r\n value=int(conf['qwen']['temperature']),\r\n help=\"模型随机性参数,数字越大,生成的结果随机性越大,一般为0.7,如果希望AI提供更多的想法,可以调大该数字\")\r\n top_p_2 = cols2[2].number_input(\"Qwen模型随机性参数top:\",\r\n max_value=10,\r\n min_value=0,\r\n value=int(conf['qwen']['top']),\r\n help=\"模型随机性参数,接近 1 时:模型几乎会考虑所有可能的词,只有概率极低的词才会被排除,随机性也越强;\")\r\n\r\n if st.button('保存配置'):\r\n try:\r\n if ai1:\r\n conf['deepseek'] = {\r\n 'choice': ai1,\r\n 'api_key': api_key_1,\r\n 'base_url': base_url_1,\r\n 'model': model_1,\r\n 'tokens': max_tokens_1,\r\n 'temperature': temperature_1,\r\n 'top': top_p_1,\r\n 'base_url_list': \",\".join(deep_base_url_list),\r\n 'model_list': \",\".join(deep_model_list)\r\n }\r\n else:\r\n conf['deepseek'] = {\r\n 'choice': ai1,\r\n 'api_key': conf['deepseek']['api_key'],\r\n 'base_url': conf['deepseek']['base_url'],\r\n 'model': conf['deepseek']['model'],\r\n 'tokens': conf['deepseek']['tokens'],\r\n 'temperature': conf['deepseek']['temperature'],\r\n 'top': conf['deepseek']['top'],\r\n 'base_url_list': conf['deepseek']['base_url_list'],\r\n 'model_list': conf['deepseek']['model_list']\r\n }\r\n if ai2:\r\n conf['qwen'] = {\r\n 'choice': ai2,\r\n 'api_key': api_key_2,\r\n 'base_url': base_url_2,\r\n 'model': model_2,\r\n 'tokens': max_tokens_2,\r\n 'temperature': temperature_2,\r\n 'top': top_p_2,\r\n 'base_url_list': \",\".join(qwen_base_url_list),\r\n 'model_list': \",\".join(qwen_model_list)\r\n }\r\n else:\r\n conf['qwen'] = {\r\n 'choice': ai2,\r\n 'api_key': conf['qwen']['api_key'],\r\n 'base_url': conf['qwen']['base_url'],\r\n 'model': conf['qwen']['model'],\r\n 'tokens': conf['qwen']['tokens'],\r\n 'temperature': conf['qwen']['temperature'],\r\n 'top': conf['qwen']['top'],\r\n 'base_url_list': conf['qwen']['base_url_list'],\r\n 'model_list': conf['qwen']['model_list']\r\n }\r\n\r\n with open(config_path, 'w', encoding='utf-8') as f:\r\n conf.write(f)\r\n with st.spinner('保存中...'):\r\n time.sleep(1)\r\n st.balloons()\r\n except:\r\n st.error(\"【接口返回结果检查】输入数据只支持json格式数据\")\r\n\r\n # AI交互\r\n with source_tab2:\r\n cases_rate_list = [60, 20, 20, 0, 0]\r\n cols3 = st.columns([2, 2])\r\n # 页面标题\r\n cols3[0].markdown(\"输入你的需求描述,AI 将为你生成相应的测试用例\")\r\n # 高级选项(可折叠)\r\n with cols3[0].expander(\"高级选项\"):\r\n show_slider = st.checkbox('用例分类占比(%)', True)\r\n cols4 = st.columns([2, 2])\r\n if show_slider:\r\n functional_testing = cols4[0].slider(\"功能用例\", min_value=0, max_value=100, value=55)\r\n boundary_testing = cols4[0].slider(\"边界用例\", min_value=0, max_value=100, value=25)\r\n exception_testing = cols4[0].slider(\"异常用例\", min_value=0, max_value=100, value=20)\r\n perfmon_testing = cols4[1].slider(\"性能/兼容性用例\", min_value=0, max_value=100, value=0)\r\n regression_testing = cols4[1].slider(\"回归测试用例\", min_value=0, max_value=100, value=0)\r\n cases_rate_list = [functional_testing,\r\n boundary_testing,\r\n exception_testing,\r\n perfmon_testing,\r\n regression_testing]\r\n test_priority = st.selectbox(\"测试优先级\", [\"--\", \"急\", \"高\", \"中\", \"低\"], index=0)\r\n # 添加测试用例数量控制\r\n test_case_count = st.number_input(\"生成测试用例数量\",\r\n min_value=0,\r\n max_value=100,\r\n value=0,\r\n step=1,\r\n help=\"指定需要生成的测试用例数量\")\r\n\r\n # 上传文件\r\n uploaded_file = cols3[0].file_uploader(\"上传需求\", type=[\"txt\"])\r\n uploaded_text = \"\"\r\n if uploaded_file is not None:\r\n uploaded_text = uploaded_file.read().decode('utf-8', 'ignore')\r\n\r\n # 用户输入区域\r\n user_input = cols3[0].text_area(\"需求描述\",\r\n height=250,\r\n value=uploaded_text,\r\n placeholder=\"请详细描述你的功能需求,例如:\\n\"\r\n \"开发一个用户注册功能 \\n\"\r\n \"1、要求用户提供用户名、密码和电子邮件,\\n\"\r\n \"2、用户名长度为3-20个字符,\\n\"\r\n \"3、密码长度至少为8个字符且必须包含数字和字母,\\n\"\r\n \"4、电子邮件必须是有效格式。\")\r\n\r\n system_writer_message = read_system_message(\"TESTCASE_WRITER_SYSTEM_MESSAGE.txt\")\r\n system_reader_message = read_system_message(\"TESTCASE_READER_SYSTEM_MESSAGE.txt\")\r\n tester_system_message = system_writer_message.replace(\"{{functional_testing}}\", str(cases_rate_list[0]))\\\r\n .replace(\"{{boundary_testing}}\", str(cases_rate_list[1]))\\\r\n .replace(\"{{exception_testing}}\", str(cases_rate_list[2]))\\\r\n .replace(\"{{perfmon_testing}}\", str(cases_rate_list[3]))\\\r\n .replace(\"{{regression_testing}}\", str(cases_rate_list[4]))\r\n # 消息模板\r\n message_tab1, message_tab2 = cols3[1].tabs([\"✍执行\", \"🔍 审核\"])\r\n with message_tab1:\r\n customer_system_message = st.text_area(\"👉消息模板预览\", height=480, value=tester_system_message)\r\n with message_tab2:\r\n customer_reader_message = st.text_area(\"👉消息模板预览\", height=480, value=system_reader_message)\r\n # 调整模型参数\r\n model_deepseek_info[\"parameters\"][\"max_tokens\"] = int(conf['deepseek']['tokens'])\r\n model_deepseek_info[\"parameters\"][\"temperature\"] = int(conf['deepseek']['temperature']) / 10\r\n model_deepseek_info[\"parameters\"][\"top_p\"] = int(conf['deepseek']['top']) / 10\r\n model_qwen_info[\"parameters\"][\"max_tokens\"] = int(conf['qwen']['tokens'])\r\n model_qwen_info[\"parameters\"][\"temperature\"] = int(conf['qwen']['temperature']) / 10\r\n model_qwen_info[\"parameters\"][\"top_p\"] = int(conf['qwen']['top']) / 10\r\n\r\n # 提交按钮\r\n submit_button = cols3[0].button(\"生成测试用例\")\r\n if submit_button:\r\n if bool(st.session_state.run_cases):\r\n st.session_state.update({\"run_cases\": False})\r\n # 处理提交\r\n if user_input:\r\n # 准备任务描述\r\n if test_priority != \"--\" and test_case_count != 0:\r\n task = f\"\"\" \r\n 需求描述: {user_input}\r\n 测试优先级: {test_priority}\r\n 【重要】请严格生成 {test_case_count} 条测试用例,不多不少。\r\n \"\"\"\r\n elif test_case_count == 0 and test_priority != \"--\":\r\n task = f\"\"\" \r\n 需求描述: {user_input}\r\n 测试优先级: {test_priority}\r\n \"\"\"\r\n elif test_case_count != 0 and test_priority == \"--\":\r\n task = f\"\"\" \r\n 需求描述: {user_input}\r\n 【重要】请严格生成 {test_case_count} 条测试用例,不多不少。\r\n \"\"\"\r\n else:\r\n task = f\"\"\" \r\n 需求描述: {user_input}\r\n \"\"\"\r\n\r\n # 创建一个固定的容器用于显示生成内容\r\n response_container = st.container()\r\n\r\n # 多角色参与生成用例\r\n async def m_roles_generate_testcases():\r\n full_response = \"\"\r\n is_continue = True\r\n text_termination = TextMentionTermination(\"APPROVE\")\r\n model_deepseek_client = OpenAIChatCompletionClient(\r\n model=conf['deepseek']['model'],\r\n base_url=conf['deepseek']['base_url'],\r\n api_key=conf['deepseek']['api_key'],\r\n model_info=model_deepseek_info,\r\n )\r\n testcase_writer = get_testcase_writer(model_deepseek_client, customer_system_message)\r\n model_qwen_client = OpenAIChatCompletionClient(\r\n model=conf['qwen']['model'],\r\n base_url=conf['qwen']['base_url'],\r\n api_key=conf['qwen']['api_key'],\r\n model_info=model_qwen_info,\r\n )\r\n testcase_reader = get_testcase_reader(model_qwen_client, customer_reader_message)\r\n team = RoundRobinGroupChat(\r\n participants=[testcase_writer, testcase_reader],\r\n termination_condition=text_termination,\r\n max_turns=10\r\n )\r\n # 创建一个空元素用于更新内容\r\n with response_container:\r\n placeholder = st.empty()\r\n async for chunk in team.run_stream(task=task):\r\n content = \"\"\r\n if chunk:\r\n # 处理不同类型的chunk\r\n if hasattr(chunk, 'content') and hasattr(chunk, 'type'):\r\n if chunk.type != 'ModelClientStreamingChunkEvent':\r\n content = chunk.content\r\n elif isinstance(chunk, str):\r\n content = chunk\r\n else:\r\n content = str(chunk)\r\n # 将新内容添加到完整响应中\r\n if is_continue and content != \"\" and not content.startswith(\"TaskResult\"):\r\n full_response += '\\n\\n' + content\r\n # 更新显示区域(替换而非追加)\r\n placeholder.markdown(full_response)\r\n # APPROVE结束退出\r\n if content.find(\"APPROVE\") > 0:\r\n is_continue = False\r\n\r\n return full_response\r\n\r\n # 单角色参与生成用例\r\n async def s_roles_generate_testcases():\r\n full_response = \"\"\r\n is_continue = True\r\n text_termination = TextMentionTermination(\"APPROVE\")\r\n model_deepseek_client = OpenAIChatCompletionClient(\r\n model=conf['deepseek']['model'],\r\n base_url=conf['deepseek']['base_url'],\r\n api_key=conf['deepseek']['api_key'],\r\n model_info=model_deepseek_info,\r\n )\r\n testcase_writer = get_testcase_writer(model_deepseek_client, customer_system_message)\r\n team = RoundRobinGroupChat(\r\n participants=[testcase_writer],\r\n termination_condition=text_termination,\r\n max_turns=1\r\n )\r\n # 创建一个空元素用于更新内容\r\n with response_container:\r\n placeholder = st.empty()\r\n async for chunk in team.run_stream(task=task):\r\n content = \"\"\r\n if chunk:\r\n # 处理不同类型的chunk\r\n if hasattr(chunk, 'content'):\r\n if chunk.type != 'ModelClientStreamingChunkEvent':\r\n content = chunk.content\r\n elif isinstance(chunk, str):\r\n content = chunk\r\n else:\r\n content = str(chunk)\r\n # 将新内容添加到完整响应中\r\n if is_continue and content != \"\" and not content.startswith(\"TaskResult\"):\r\n full_response += '\\n\\n' + content\r\n # 更新显示区域(替换而非追加)\r\n placeholder.markdown(full_response)\r\n # APPROVE结束退出\r\n if content.find(\"APPROVE\") > 0:\r\n is_continue = False\r\n\r\n return full_response\r\n\r\n # 重新拉取消息\r\n def show_message(message):\r\n case_list_new = format_testcases(message)\r\n with response_container:\r\n placeholder = st.empty()\r\n placeholder.markdown(message)\r\n st.success(\"✅ 测试用例生成完成!\")\r\n st.download_button(\r\n label=\"下载测试用例(.md)\",\r\n data=\"\\n\".join(case_list_new),\r\n file_name=\"测试用例.md\",\r\n mime=\"text/markdown\",\r\n icon=\":material/markdown:\",\r\n )\r\n\r\n st.download_button(\r\n label=\"下载测试用例(.xlsx)\",\r\n data=output.getvalue(),\r\n file_name=\"测试用例.xlsx\",\r\n mime=\"application/vnd.ms-excel\",\r\n icon=\":material/download:\",\r\n )\r\n\r\n if eval(conf['deepseek']['choice']) and eval(conf['qwen']['choice']):\r\n if conf['deepseek']['api_key'] != \"\" and conf['qwen']['api_key'] != \"\":\r\n try:\r\n with st.spinner(\"正在生成测试用例...\"):\r\n result = asyncio.run(m_roles_generate_testcases())\r\n case_list = format_testcases(result)\r\n st.success(\"✅ 测试用例生成完成!\")\r\n if len(case_list):\r\n st.download_button(\r\n label=\"下载测试用例(.md)\",\r\n data=\"\\n\".join(case_list),\r\n file_name=\"测试用例.md\",\r\n mime=\"text/markdown\",\r\n icon=\":material/markdown:\",\r\n on_click=show_message,\r\n args=(result,),\r\n )\r\n output = BytesIO()\r\n workbook = xlsxwriter.Workbook(output, {'in_memory': True})\r\n worksheet = workbook.add_worksheet()\r\n for row, case in enumerate(case_list):\r\n if case.find(\"--------\") < 0:\r\n for col, cell in enumerate(case.split(\"|\")):\r\n if col > 0:\r\n if row > 1:\r\n worksheet.write(row-1, col-1, str(cell).strip())\r\n else:\r\n worksheet.write(row, col-1, str(cell).strip())\r\n workbook.close()\r\n st.download_button(\r\n label=\"下载测试用例(.xlsx)\",\r\n data=output.getvalue(),\r\n file_name=\"测试用例.xlsx\",\r\n mime=\"application/vnd.ms-excel\",\r\n icon=\":material/download:\",\r\n on_click=show_message,\r\n args=(result,),\r\n )\r\n except Exception as e:\r\n st.error(f\"生成测试用例时出错: {str(e)}\")\r\n else:\r\n st.error(\"请先配置DeepSeek/Qwen模型的APIKEY!\")\r\n elif eval(conf['deepseek']['choice']) and not eval(conf['qwen']['choice']):\r\n if conf['deepseek']['api_key'] != \"\":\r\n try:\r\n with st.spinner(\"正在生成测试用例...\"):\r\n result = asyncio.run(s_roles_generate_testcases())\r\n case_list = format_testcases(result)\r\n st.success(\"✅ 测试用例生成完成!\")\r\n if len(case_list):\r\n st.download_button(\r\n label=\"下载测试用例(.md)\",\r\n data=\"\\n\".join(case_list),\r\n file_name=\"测试用例.md\",\r\n mime=\"text/markdown\",\r\n icon=\":material/markdown:\",\r\n on_click=show_message,\r\n args=(result,),\r\n )\r\n output = BytesIO()\r\n workbook = xlsxwriter.Workbook(output, {'in_memory': True})\r\n worksheet = workbook.add_worksheet()\r\n for row, case in enumerate(case_list):\r\n if case.find(\"--------\") < 0:\r\n for col, cell in enumerate(case.split(\"|\")):\r\n if col > 0:\r\n if row > 1:\r\n worksheet.write(row - 1, col - 1, str(cell).strip())\r\n else:\r\n worksheet.write(row, col - 1, str(cell).strip())\r\n workbook.close()\r\n st.download_button(\r\n label=\"下载测试用例(.xlsx)\",\r\n data=output.getvalue(),\r\n file_name=\"测试用例.xlsx\",\r\n mime=\"application/vnd.ms-excel\",\r\n icon=\":material/download:\",\r\n on_click=show_message,\r\n args=(result,),\r\n )\r\n except Exception as e:\r\n st.error(f\"生成测试用例时出错: {str(e)}\")\r\n else:\r\n st.error(\"请先配置DeepSeek模型的APIKEY!\")\r\n else:\r\n st.error(\"请先配置DeepSeek模型并选中保存!\")\r\n st.session_state.update({\"run_cases\": True})\r\n\r\n elif submit_button and not user_input:\r\n st.error(\"请输入需求描述\")\r\n st.session_state.update({\"run_cases\": True})\r\n else:\r\n st.warning(\"正在生成测试用例中,请不要频繁操作!\")\r\n return None\r\n\r\n\r\nif __name__ == '__main__':\r\n main()\r\n"}}}}