diff --git a/api/constants.py b/api/constants.py index 44563e7..9b4dc08 100644 --- a/api/constants.py +++ b/api/constants.py @@ -41,3 +41,6 @@ TEAM_LEADER = "teamLeader" RISK_LEVEL = "riskLevel" #班组名称 TEAM_NAME = "teamName" + +PAGE = "page" +PROGRAM_NAVIGATION = "programNavigation" diff --git a/api/main.py b/api/main.py index 08af9fe..f61c921 100644 --- a/api/main.py +++ b/api/main.py @@ -16,7 +16,8 @@ from globalData import GlobalData from apscheduler.schedulers.background import BackgroundScheduler MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-14672" -MODEL_UIE_PATH = R"../uie/output/checkpoint-18190" +MODEL_UIE_PATH = R"../uie/output/checkpoint-16380" + # 类别名称列表 labels = [ @@ -295,7 +296,8 @@ def extract_multi_chat(messages): logger.info(f"oldest_chat_history:{oldest_chat_history}") prompt = f''' - 你是一个意图识别与补全助手,你的任务是根据用户的最新问题判断是否需要补全,如果不需要补全,则原样返回用户的最新问题,否则需要结合最新对话历史和最老对话历史补全用户的最新问题,并只返回最终的完整问题。请严格按照如下逻辑判断并执行: + 你是一个意图识别与补全助手,你的任务是根据用户的最新问题判断是否需要补全,如果不需要补全,则原样返回用户的最新问题,否则需要结合最新对话历史和最老对话历史补全用户的最新问题,并只返回最终的完整问题。 + 请严格按照如下逻辑判断并执行: --- @@ -333,9 +335,9 @@ def extract_multi_chat(messages): 第二步:用户最新问题是否为序号指代(第一个/第2个)?→ 用完整工程/项目/公司名替换补全 - 精确提取用户所指的序号(如“第3个”指第3个工程名、公司名或项目部名); - 将该工程、公司或项目部的完整名称(包括括号中的编号)提取出来; - - 用完整工程、公司或项目部的名称替换掉最新对话历史的用户问题中出现的简称或模糊表达,但保留其他信息不变; - - 必须保留最新对话历史的用户问题中的所有其他关键信息(如具体的动作和操作的内容包括但不限于:项目部名称、时间、计划数、内容如"进度情况""作业计划""作业内容"“摄像头”“视频”等); + - 用完整工程、公司或项目部的名称替换掉最新对话历史的用户问题中出现的简称或模糊表达,但保留用户问题中的其余所有内容,包括操作动词(如“打开”“查一下”)、时间和目标对象(如“摄像头”、“视频”、"进度情况""作业计划""作业内容")等,不得遗漏; - 禁止添加用户原始问题中未出现的动作性动词(例如:“打开”“查看”“查询”“显示”“展示”等); + - 最终问题必须贴近原始提问语气和意图,只替换模糊对象的全称,不改变句式和动作行为表达; - 示例1: - 用户最新问题:"第二个" 或"第2个" - 最新对话历史的用户问题:"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划"" diff --git a/api/main_temp.py b/api/main_temp.py index 5e0a664..3c4ba9d 100644 --- a/api/main_temp.py +++ b/api/main_temp.py @@ -15,8 +15,9 @@ from config import * from globalData import GlobalData from apscheduler.schedulers.background import BackgroundScheduler -MODEL_ERNIE_PATH = R"../ernie/output_temp/checkpoint-29288" -MODEL_UIE_PATH = R"../uie/output_temp/checkpoint-36320" +MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-14672" +MODEL_UIE_PATH = R"../uie/output/checkpoint-18190" + # 类别名称列表 labels = [ @@ -278,14 +279,14 @@ def extract_multi_chat(messages): latest_user_question = latest_message.content if latest_message.role == "user" else "" time_prefixes = ["当前","今天", "昨天", "本周", "下周", "明天", "今日","打开"] - history_messages = [] if any(prefix in latest_user_question and prefix != latest_user_question for prefix in time_prefixes) else messages[:-1] + history_messages = [] if any(prefix in latest_user_question and len(latest_user_question) > 3 for prefix in time_prefixes) else messages[:-1] logger.info(f"len(history_messages):{len(history_messages)}") #最新问题的上一个问题里如果含有时间,则清空最老的历史对话 last_two_messages = history_messages[-2:] has_time_prefix = any( - msg.role == "user" and any(prefix in msg.content and prefix != msg.content for prefix in time_prefixes) + msg.role == "user" and any(prefix in msg.content and len(msg.content) > 3 for prefix in time_prefixes) for msg in last_two_messages ) last_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in last_two_messages]) @@ -295,50 +296,69 @@ def extract_multi_chat(messages): logger.info(f"oldest_chat_history:{oldest_chat_history}") prompt = f''' - 你是一个意图识别与补全助手,你的任务是根据用户的最新问题判断是否需要补全,如果不需要补全,则原样返回用户的最新问题,否则需要结合最新对话历史和最老对话历史补全用户的最新问题,并只返回最终的完整问题。请严格按照如下逻辑判断并执行: + 你是一个意图识别与补全助手,你的任务是根据用户的最新问题判断是否需要补全,如果不需要补全,则原样返回用户的最新问题,否则需要结合最新对话历史和最老对话历史补全用户的最新问题,并只返回最终的完整问题。 + 请严格按照如下逻辑判断并执行: --- 【规则判断与补全流程】 - 第一步:用户最新问题是否存在指代词?→ 结合用户最新问题和最新对话历史进行补全 - - 若用户最新问题问题中出现模糊表达,如“具体是哪些项”、“是哪两个”、“作业计划分别是什么”、“合肥中心变工程呢”、“具体是哪20项”、“考勤人数呢”等,请根据需要结合最新对话历史或最老对话历史补全问题信息。 + 第一步:用户最新问题是否存在指代词?→ 结合用户最新问题和历史用户问题进行补全 + - 若用户最新问题中出现模糊表达,如“具体是哪些项”、“是哪两个”、“作业计划分别是什么”、“合肥中心变工程呢”、“具体是哪20项”、“考勤人数呢”等,请根据需要结合最新对话历史和最老对话历史的补全问题信息; + - 需要补全的信息包括时间、主语、查询对象等; + - **特别地,若最新用户问题中未提及时间,但最新对话历史中的用户问题中出现“今天”“昨日”“本周”等时间词,则需要将其补全进最终问题中;** + - **特别地,若最新用户问题中未提及时间,但最老对话历史中的用户问题中出现“今天”“昨日”“本周”等时间词,则需要将其补全进最终问题中;** - 示例1: - - 用户最新问题:“具体的作业计划分别是什么” - - 最新对话历史的用户问题:“今天公司有多少项作业计划” - - 最新对话历史的AI回答:“2025-04-25公司一共有421项作业计划,分别如下:风险等级为2级的有15项,3级的有144项,4级的有262项,5级的有0项” - - 则最终提问应为: - “今天公司的421项作业计划分别是什么” - - 示例2: - 用户最新问题:“具体的作业内容是什么” - - 最新对话历史的用户问题:送一分公司第一项目部今天有多少项作业计划 - - 最新对话历史的AI回答:今天送电一分公司第一项目管理部有21项作业计划 + - 最新对话历史的用户问题:“送一分公司第一项目部今天有多少项作业计划” + - 最新对话历史的AI回答:“送电一分公司第一项目管理部有21项作业计划” - 则最终提问应为: “今天送电一分公司第一项目管理部的21项作业计划分别是什么” + - 示例2: + - 用户最新问题:“2项作业计划是什么” + - 最老对话历史的用户问题:“宋1分公司第一项目部今天有多少作业计划” + - 最老对话历史的AI回答:“未匹配到您说的分公司名:宋1分公司,请提供更准确的分公司名” + - 最新对话历史的用户问题:“送一分公司” + - 最新对话历史的AI回答:“送电一分公司第一项目管理部有2项作业计划” + - 则最终提问应为: + “今天送电一分公司第一项目管理部的2项作业计划是什么” + + - 示例3: + - 用户最新问题:“具体的班组详情” + - 最新对话历史的用户问题:“送一分公司第一项目部今天有多少班组” + - 最新对话历史的AI回答:“送电一分公司第一项目部(金上)有20个班组” + - 则最终提问应为: + “送电一分公司第一项目部(金上)今天具体的20个班组详情” + + 第二步:用户最新问题是否为序号指代(第一个/第2个)?→ 用完整工程/项目/公司名替换补全 - 精确提取用户所指的序号(如“第3个”指第3个工程名、公司名或项目部名); - 将该工程、公司或项目部的完整名称(包括括号中的编号)提取出来; - - 用完整工程、公司或项目部的名称替换掉最新对话历史的用户问题中出现的简称或模糊表达,但保留其他信息不变; - - 必须保留最新对话历史的用户问题中的所有其他关键信息(如具体的动作和操作的内容包括但不限于:项目部名称、时间、计划数、内容如"进度情况""作业计划""作业内容"“摄像头”“视频”等); + - 用完整工程、公司或项目部的名称替换掉最新对话历史的用户问题中出现的简称或模糊表达,但保留用户问题中的其余所有内容,包括操作动词(如“打开”“查一下”)、时间和目标对象(如“摄像头”、“视频”、"进度情况""作业计划""作业内容")等,不得遗漏; + - 禁止添加用户原始问题中未出现的动作性动词(例如:“打开”“查看”“查询”“显示”“展示”等); + - 最终问题必须贴近原始提问语气和意图,只替换模糊对象的全称,不改变句式和动作行为表达; - 示例1: - 用户最新问题:"第二个" 或"第2个" - 最新对话历史的用户问题:"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划"" - 最新对话历史的AI回答:你说的工程名可能是,第一个:检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179),第二个:黄阳-仙河110kV线路工程(PROJ-2024-0047),请确认您要选择哪一个? - 则最终提问应为: - `黄阳-仙河110kV线路工程(PROJ-2024-0047))今天有多少作业计划` + "黄阳-仙河110kV线路工程(PROJ-2024-0047))今天有多少作业计划" + - 示例2: - 用户最新问题:"第2个" 或"第二个" - - 紧最新对话历史的用户问题:"请帮我查一下今天芦集变电站的进度情况" + - 最新对话历史的用户问题:"请帮我查一下今天芦集变电站的进度情况" - 最新对话历史的AI回答:你说的工程名可能是,第1个:芦集-古沟π入潘集变电站220kV线路工程(PROJ-2024-0189),第二个:淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265),请确认您要选择哪一个? - 则最终提问应为: "请帮我查一下今天淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265)的进度情况" + - 示例3: - 用户最新问题:"第2个" - 最新对话历史的用户问题:"宏源电力公司第三项目部今天有多少项作业计划" - 最新对话历史的AI回答:您说的实施组织名可能是,第1个:安徽宏源电力建设有限公司(线路),第2个:安徽宏源电力建设有限公司(变电),请选择哪一个 - 则最终提问应为: "安徽宏源电力建设有限公司(变电)第三项目部今天有多少项作业计划" + - 示例4: - 用户最新问题:"第2个" - 最新对话历史的用户问题:"打开中心变摄像头" @@ -346,6 +366,13 @@ def extract_multi_chat(messages): - 则最终提问应为: "打开合肥中心变B包(PROJ-2024-0176)摄像头" + - 示例5: + - 最新对话历史的用户问题:“今天循环园工程有多少项作业计划” + - 最新对话历史的AI回答:“您说的工程名可能是:第1个... 第2个... 第3个:黄山巷联-水西220kV线路工程(PROJ-2024-0220),请确认您要选择哪一个?” + - 用户最新问题:“第3个” + - 错误输出(不要这样):“打开黄山巷联-水西220kV线路工程(PROJ-2024-0220)今天有多少项作业计划” + - 正确输出(你应该输出):“黄山巷联-水西220kV线路工程(PROJ-2024-0220)今天有多少项作业计划” + 第三步:输出最终问题 - 直接输出最终问题(无解释、无多余前缀或后缀) - 保持句式自然清晰 @@ -366,6 +393,7 @@ def extract_multi_chat(messages): {"role": "user", "content": prompt} ] + # logger.info(f"*********messages:{prompt}") response = client.chat.completions.create( messages=message, model=model_name, diff --git a/api/slotRecognition.py b/api/slotRecognition.py index 7a3ebe0..6f169d3 100644 --- a/api/slotRecognition.py +++ b/api/slotRecognition.py @@ -3,7 +3,7 @@ from paddlenlp.transformers import ErnieForTokenClassification, ErnieTokenizer from globalData import GlobalData from utils import standardize_name_only_high_score, clean_useless_company_name -from constants import SUBCONTRACTOR, CONSTRUCTION_UNIT, IMPLEMENTATION_ORG +from constants import SUBCONTRACTOR, CONSTRUCTION_UNIT, IMPLEMENTATION_ORG, PAGE, PROGRAM_NAVIGATION import paddle.nn.functional as F @@ -149,7 +149,7 @@ class SlotRecognition: for key, value in entities.items(): value = value.replace('#', '') # 暂时不支持分包商和监管单位的查询 - if (key == SUBCONTRACTOR or key == CONSTRUCTION_UNIT or key == IMPLEMENTATION_ORG) : + if key == SUBCONTRACTOR or key == CONSTRUCTION_UNIT or key == IMPLEMENTATION_ORG: # print(f"recognize_probability- key:{key},value:{value}") match_results = standardize_name_only_high_score(value,clean_useless_company_name, GlobalData.simply_to_standard_company_name_map, GlobalData.pinyin_simply_to_standard_company_name_map, 90) if match_results: @@ -171,6 +171,12 @@ class SlotRecognition: else: updates[key] = value prob_updates[key] = slot_probabilities[key] + elif key == PROGRAM_NAVIGATION or key == PAGE: + if "施" in value: + updates[key] = "施工生产管理平台" + else: + updates[key] = value + prob_updates[key] = slot_probabilities[key] else: updates[key] = value prob_updates[key] = slot_probabilities[key] diff --git a/generated_data/generated.py b/generated_data/generated.py index e2fe397..f09f373 100644 --- a/generated_data/generated.py +++ b/generated_data/generated.py @@ -69,7 +69,7 @@ BASE_DATA = { "subcontractors": ["劦力建筑责任公司","安徽劦力建筑装饰有限责任公司", "安徽苏亚建设集团有限公司","大信电力建设有限公司","优越电力公司", "安徽国腾电力工程有限公司","安徽京硚建设有限公司","中国能源建设集团安徽省电力设计院有限公司","作业班组管理中心"], # 班组名称 - "team_names": ["张朵班组", "刘梁玉班组", "魏玉龙班组","周可富班组"], + "team_names": ["张朵班组", "刘梁玉班组", "魏玉龙班组","周可富班组","齐中文班组"], # 班组长 "team_leaders": ["李元帅班组长", "刘雨豪班组长"], # 风险等级 @@ -78,7 +78,8 @@ BASE_DATA = { "operatings": ["8+2工况", "8加2工况"], # 页面切换 "pages": ["风险管控", "日计划", "周风险", "日计划统计报表", "日计划推送", "生产管控中心", "考勤统计详情", - "今日作业计划", "周风险统计报表", "周风险推送"], + "今日作业计划", "周风险统计报表", "周风险推送", "进度管理", "技术管理", "项目团队", "质量管理", + "云上会议", "项目巡航", "施工生产管理平台"], # 具体人名 "person_names": ["何东洋", "李东","王孙强林"], # 人名查询目标 @@ -91,8 +92,6 @@ BASE_DATA = { "sky_nets": ["摄像头", "视频"], #项目巡航 "program_navigations": ["数字化项目部", "数字化项目部管理平台", "施工生产管理平台"], - - } # 自然语言模板配置 @@ -750,24 +749,21 @@ TEMPLATE_CONFIG = { ("打开{page}页面", ["page"]), ("打开{page}", ["page"]), ("切换{page}模块", ["page"]), - ("进入{page}", ["page"]), - ("进入{page}模块", ["page"]), ("切换到{page}页面", ["page"]), - ("跳转到{page}", ["page"]), + ("跳转到{page}。", ["page"]), ("跳转到{page}模块", ["page"]), ("切换到{page}页面", ["page"]), - ("访问{page}页面", ["page"]), ("切换{page}模块", ["page"]), - ("访问{page}", ["page"]), ("请打开{page}模块", ["page"]), - ("请打开{page}", ["page"]), + ("请打开{page}。", ["page"]), ("请切换到{page}页面", ["page"]), - ("加载{page}模块", ["page"]), ("切换{page}", ["page"]), - ("加载{page}页面", ["page"]), #施工生产管理平台 + ("打开{program_navigation}", ["program_navigation"]), + ("打开{program_navigation}。", ["program_navigation"]), #项目巡航:分公司 ("打开{implementation_organization}{program_navigation}", ["implementation_organization", "program_navigation"]), + ("打开{implementation_organization}{program_navigation}。", ["implementation_organization", "program_navigation"]), #项目巡航:分公司、项目部 ("打开{implementation_organization}{project_department}{program_navigation}", ["implementation_organization", "project_department", "program_navigation"]), @@ -778,8 +774,11 @@ TEMPLATE_CONFIG = { ("打开{project_name}{program_navigation}", ["project_name", "program_navigation"]), #皖智天网,工程名摄像头 ("打开{project_name}{sky_net}", ["project_name", "sky_net"]), + ("切换到{project_name}{sky_net}", ["project_name", "sky_net"]), #皖智天网,班组名摄像头 - ("切换到{team_leader}{sky_net}", ["team_leader", "sky_net"]), + ("切换到{team_name}{sky_net}", ["team_name", "sky_net"]), + ("切换{team_name}{sky_net}", ["team_name", "sky_net"]), + ("打开{team_name}{sky_net}", ["team_name", "sky_net"]), #施工生产管理平台 ] }, @@ -1067,6 +1066,9 @@ TEMPLATE_CONFIG = { ("{date}工程性质为{project_type}班组详情?", ["date", "project_type"]), ("公司工程性质为{project_type}{date}具体有哪些班组?", ["project_type", "date"]), ("公司工程性质为{project_type}{date}班组有哪些?", ["project_type", "date"]), + #班组 + ("{date}{team_name}具体哪20人", ["date", "team_name"]), + ("{date}{team_name}人员情况", ["date", "team_name"]), #建管单位所在地区 ("{construction_area}地区{date}具体班组详情是什么?", ["construction_area", "date"]),