Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
jiang 2025-03-03 13:18:38 +08:00
commit 68ec32a697
7 changed files with 17123 additions and 45 deletions

3
api/config.py Normal file
View File

@ -0,0 +1,3 @@
api_base_url = "http://36.33.26.201:27861/v1"
api_key = 'EMPTY'
model_name = 'qwen2.5-instruct'

22
api/constants.py Normal file
View File

@ -0,0 +1,22 @@
# constants.py
SIMILARITY_VALUE = 0.7
#日期
DATE = "date"
#工程名称
PROJECT_NAME = "projectName"
#工程性质
PROJECT_TYPE = "projectType"
#建管单位
CONSTRUCTION_UNIT = "constructionUnit"
#分公司
IMPLEMENTATION_ORG = "implementationOrganization"
#项目部
PROJECT_DEPARTMENT = "projectDepartment"
#项目经理
PROJECT_MANAGER = "projectManager"
#分包商
SUBCONTRACTOR = "subcontractor"
#班组
TEAM_LEADER = "teamLeader"
#风险
RISK_LEVEL = "riskLevel"

View File

@ -9,12 +9,16 @@ import paddle.nn.functional as F # 用于 Softmax
from typing import List, Dict
from pydantic import ValidationError
from api.intentRecognition import IntentRecognition
from api.slotRecognition import SlotRecognition
from intentRecognition import IntentRecognition
from slotRecognition import SlotRecognition
from fuzzywuzzy import process
from utils import CheckResult, StandardType, load_standard_name
from constants import PROJECT_NAME, PROJECT_DEPARTMENT, SIMILARITY_VALUE
from config import *
# 常量
MODEL_ERNIE_PATH = R"E:\workingSpace\PycharmProjects\Intention_dev\ernie\output\checkpoint-4160"
MODEL_UIE_PATH = R"E:\workingSpace\PycharmProjects\Intention_dev\uie\uie_ner\checkpoint-4320"
MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-4160"
MODEL_UIE_PATH = R"../uie/output/checkpoint-4320"
# 类别名称列表
labels = [
@ -36,15 +40,22 @@ label_map = {
10: 'B-riskLevel', 20: 'I-riskLevel'
}
# 初始化工具类
intent_recognizer = IntentRecognition(MODEL_ERNIE_PATH, labels)
# 初始化槽位识别工具类
slot_recognizer = SlotRecognition(MODEL_UIE_PATH, label_map)
# 设置Flask应用
#标准工程名
standard_project_name_list = load_standard_name('./standard_data/standard_project.txt')
#标准项目名
standard_program_name_list = load_standard_name('./standard_data/standard_program.txt')
print(f":standard_project_name_list:{standard_project_name_list}")
app = Flask(__name__)
# 统一的异常处理函数
@app.errorhandler(Exception)
def handle_exception(e):
@ -117,7 +128,7 @@ def intent_reco():
return user_validation_error
# 调用predict方法进行意图识别
predicted_label, predicted_probability,predicted_id = intent_recognizer.predict(text)
predicted_label, predicted_probability, predicted_id = intent_recognizer.predict(text)
return jsonify(
code=200,
@ -190,76 +201,146 @@ def agent():
predicted_label, predicted_probability, predicted_id = intent_recognizer.predict(query)
# 再进行槽位抽取
entities = slot_recognizer.recognize(query)
status, sk = check_lost(predicted_label, entities)
# 返回意图和槽位识别的结果
return jsonify({
"code": 200,
"msg": "成功",
"answer": {
"int": predicted_id,
"label": predicted_label,
"probability": predicted_probability,
"slot": entities
},
})
print(f"第一轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},message:{messages}")
# 如果是后续轮次(多轮对话),这里只做示例,可能需要根据具体需求进行处理
else:
query = messages[0].content # 使用 Message 对象的 .content 属性
# 先进行意图识别
predicted_label, predicted_probability, predicted_id = intent_recognizer.predict(query)
entities = multi_slot_recognizer(predicted_id, messages)
print(f"多轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},message:{messages}")
#必须槽位缺失检查
status, sk = check_lost(predicted_id, entities)
if status == CheckResult.NEEDS_MORE_ROUNDS:
return jsonify({"code": 10001, "msg": "成功",
"answer": { "miss": sk},
})
#工程名和项目名标准化
print(f"start to check_project_standard_slot")
result, information = check_project_standard_slot(predicted_id, entities)
print(f"end check_project_standard_slot,{result},{information}")
if result == CheckResult.NEEDS_MORE_ROUNDS:
return jsonify({
"user_id": user_id,
"query": query,
"message_count": len(messages)
"code": 10001, "msg": "成功",
"answer": {"miss": information},
})
return jsonify({
"code": 200,"msg": "成功",
"answer": {"int": predicted_id, "label": predicted_label, "probability": predicted_probability, "slot": entities },
})
except ValidationError as e:
return jsonify({"error": e.errors()}), 400 # 捕捉 Pydantic 错误并返回
except Exception as e:
return jsonify({"error": str(e)}), 500 # 捕捉其他错误并返回
def multi_slot_recognizer(intention_id, messages):
from openai import OpenAI
client = OpenAI(base_url = api_base_url, api_key = api_key)
prompt = f'''
根据用户的输入{messages}抽取出用户想了解的问题要求保持客观真实简单明了不要多余解释和阐述
'''
message = [{"role": "system", "content": prompt}]
message.extend(messages)
# print(message)
response = client.chat.completions.create(
messages=message,
model=model_name,
max_tokens=1000,
temperature=0.001,
stream=False
)
res = response.choices[0].message.content
print(f"多轮意图后用户想要的问题是{res}")
entries = slot_recognizer.recognize(res)
return entries
def check_lost(int_res, slot):
# mapping = {
# "页面切换":[['页面','应用']],
# "作业计划数量查询":[['时间']],
# "周计划查询":[['时间']],
# "作业内容":[['时间']],
# "施工人数":[['时间']],
# "作业考勤人数":[['时间']],
# }
#labels: ["天气查询","互联网查询","页面切换","日计划数量查询","周计划数量查询","日计划作业内容","周计划作业内容","施工人数","作业考勤人数","知识问答"]
mapping = {
1: [['date', 'area']],
3: [['page'], ['app'], ['module']],
2: [['page'], ['app'], ['module']],
3: [['date']],
4: [['date']],
5: [['date']],
6: [['date']],
7: [['date']],
8: [[]],
9: [[]],
8: [['date']],
}
intention_mapping = {2: "页面切换", 3: "日计划数量查询", 4: "周计划数量查询", 5: "日计划作业内容",
6: "周计划作业内容",7: "施工人数",8: "作业考勤人数"}
if not mapping.__contains__(int_res):
return 0, []
return 0, ""
#提取的槽位信息
cur_k = list(slot.keys())
idx = -1
idx_len = 99
for i in range(len(mapping[int_res])):
sk = mapping[int_res][i]
left = [x for x in sk if x not in cur_k]
more = [x for x in cur_k if x not in sk]
if len(more) >= 0 and len(left) == 0:
#不在提取的槽位信息里,但是在必须槽位表里
miss_params = [x for x in sk if x not in cur_k]
#不在必须槽位表里,但是在提取的槽位信息里
extra_params = [x for x in cur_k if x not in sk]
if len(extra_params) >= 0 and len(miss_params) == 0:
idx = i
idx_len = 0
break
if len(left) < idx_len:
if len(miss_params) < idx_len:
idx = i
idx_len = len(left)
idx_len = len(miss_params)
if idx_len == 0: # 匹配通过
return 0, cur_k
return CheckResult.NO_MATCH, cur_k
#符合当前意图的的必须槽位,但是不在提取的槽位信息里
left = [x for x in mapping[int_res][idx] if x not in cur_k]
return 1, left # mapping[int_res][idx]
print(f"符合当前意图的的必须槽位,但是不在提取的槽位信息里, {left}")
apologize_str = "非常抱歉,"
if int_res == 2:
return CheckResult.NEEDS_MORE_ROUNDS, f"{apologize_str}请问你想查询哪个页面?"
elif int_res in [3, 4, 5, 6, 7, 8]:
return CheckResult.NEEDS_MORE_ROUNDS, f"{apologize_str}请问你想查询什么时间的{intention_mapping[int_res]}"
#标准化工程名
def check_project_standard_slot(int_res, slot) -> tuple:
intention_list = {3, 4, 5, 6, 7, 8}
if int_res not in intention_list:
return CheckResult.NO_MATCH, ""
for key, value in slot.items():
if key == PROJECT_NAME:
match_project, match_possibility = fuzzy_match(value, standard_project_name_list)
print(f"fuzzy_match project result:{match_project}, {match_possibility}")
if match_possibility >= SIMILARITY_VALUE:
slot[key] = match_project
else:
return CheckResult.NEEDS_MORE_ROUNDS, f"抱歉,您说的工程名是{match_project}"
if key == PROJECT_DEPARTMENT:
match_program, match_possibility = fuzzy_match(value, standard_program_name_list)
print(f"fuzzy_match program result:{match_program}, {match_possibility}")
if match_possibility >= SIMILARITY_VALUE:
slot[key] = match_program
else:
return CheckResult.NEEDS_MORE_ROUNDS, f"抱歉,您说的项目名是{match_program}"
return CheckResult.NO_MATCH, ""
def fuzzy_match(user_input, standard_name):
result = process.extract(user_input, standard_name)
return result[0][0], result[0][1]/100
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
app.run(host='0.0.0.0', port=18074, debug=True)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,199 @@
杨柳220kV变电站220kV南坪间隔扩建工程
阜阳东坡110kV变电站新建工程
杨柳圩110kV变电站110kV配电装置改造工程
阜阳太和城南110kV变电站新建工程
安庆石化110kV变电站新建 工程
华南城220kV变电站新建工程
马鞍山万济220kV变电站新建工程
紫蓬500kV变电站间隔扩建工程
安徽阜阳阜四500kV变电站新建工程
安徽合肥杜岗220kV开关站新建工程
庐北220kV变电站新建工程
渝北±800千伏换流站工程电气安装A包
宿州城东220kV变电站新建工程
马鞍山金河口110kV变电站新建工程
安庆四500kV变电站新建工程
合肥循环园220kV变电站新建工程
马鞍山郑蒲220kV变电站新建工程
国网安徽宣城供电公司500kV河沥变加装固定融冰装置
滁州堰陈110千伏变电站新建工程
安徽河沥500kV变电站3号主变扩建工程
安徽合肥义兴220kV变电站新建工程
宣城中港110kV变电站新建工程
安庆城南110kV变电站新建工程
国网安徽安庆供电公司500kV双岭变电站加装固定融冰装置
芜湖蛟矶220kV变电站新建工程
国网安徽马鞍山供电公司220kV恒兴变电站220kV配电装置改造
马鞍山横龙110kV变电站新建工程
金牛500kV变电站新建工程
安庆双港220kV变电站新建工程
安庆银山220kV变电站新建工程
芜湖高村220kV变电站新建工程
滁州红桥220kV变电站新建工程
安徽合肥方兴II110kV变电站新建工程
银联黄山园区220kV变电站工程
陕北-安徽±800千伏特高压直流输电工程陶大庄村接地极工程
松滋-安丰220kV线路工程
伯阳500千伏变电站220千伏间隔扩建工程
道轩汇流站-伯阳 220kV 线路工程
香涧-梨花220kV线路工程
埇桥-萧砀回500千伏线路工程
埇桥-萧砀Ⅱ回500千伏线路工程
石岗-施桥110kV线路工程
芦集-古沟π入潘集变电站220kV线路工程
黄阳-仙河110kV线路工程
淮南芦集220千伏变电站220千伏配电装置改造工程
伯阳-谯城500kV线路工程
魏武-桐花π入祝集变电站110kV线路工程
耿皇-焦楼220kV线路工程
蕴山-沙埂110kV线路工程
蚌埠孝仪220kV变电站新建工程建筑安装部分
安徽六安春秋塘-山七π入汤池变电站110kV线路工程
亳州城北110kV变电站新建工程
蚌埠潼河110kV变电站新建工程
沪宁合高铁安徽段500kV清同5737线等2处电力线路迁改工程
伯阳-涡阳π入真源变电站220kV线路工程
濉淮5379濉洪5380线147#-148#跨阜淮铁路迁改工程
汤庄-平圩500kV线路工程
换流站-金牛500kV线路工程
包河10kV玉龙18网架结构化工程施工
淮南安丰220千伏变电站新建工程
祝集220kV变电站新建工程
田家庵电厂秦集改接孝仪变电站220kV线路工程
谯城500千伏变电站新建工程建筑
金牛500kV变电站新建工程建筑
陕北-安徽直流工程合州±800千伏换流站土建A包
锁库500kV变电站新建工程
安徽宿州萧砀500千伏变电站新建工程建筑部分
合肥中心变B包
中心500kV变电站新建工程A包
国网北京检修公司2024年±500kV延庆换流站直流主设备及辅助设备不停电检修维护
香涧-鹭岛500kV线路工程一般线路东段
香涧-鹭岛500kV线路工程淮河大跨越段
安徽滁州清流-环漪220kV线路改造工程
香涧-鹭岛500kV线路工程一般线路西段
谢桥电厂-原鹿220kV线路工程
阜四-椿树220千伏线路工程
寨西-苦竹溪T接金桥变电站110kV线路工程
韦寨-范兴集π入阜四变电站220kV线路工程
金牛-福渡500kV线路工程巢湖、无为段
金牛-福渡500kV线路工程庐江段
安徽马鞍山当涂-万济220kV线路工程
黄山巷联-水西220kV线路工程
苍山-横龙110kV架空线路工程
安徽马鞍山围屏-万济220kV线路工程
甘肃-浙江±800千伏特高压直流输电线路工程皖3标段
广德-敬亭π入桂花广五变220kV线路工程
绿雪-莲塘220kV线路工程
芜湖福渡-蛟矶220kV线路工程
塔岗-西梁山T接杨柳圩变电站110kV架空线路工程
芜湖江北-通江π入蛟矶变电站220kV线路工程
含山-环峰T接横龙110kV架空线路工程
安徽宣城莲塘-敬亭220kV线路改造工程
月桥-火龙岗π入高村变电站220kV线路工程
太和-李腰π入城南变电站110kV架空线路工程
文昌宫-淮北西牵引站220kV线路工程
杨柳四铺π入况楼变110kV电缆线路工程
陕北-安徽±800kV特高压直流输电线路工程皖2标
安徽合肥晶合220kV外部供电工程合肥杜岗Ⅱ220kV输变电工程
肥西-中心500kV线路工程电缆部分
池州电厂二期-涓桥220kV线路工程
陶楼-下塘、陶楼-航锂凯博π入下塘变电站220kV电缆线路工程
显通-白杨T接刘桥、显通-溪河T接刘桥π入凌云变电站110kV架空线路工程
南屏-蓬莱路π入派河变电站110kV线路工程
茗南-熙湖T接城南变电站110kV架空线路工程
显通-碱河π入凌云变电站220kV电缆线路工程
灵泗-奎河220kV线路工程
合肥二电厂-长临河π入循环园变电站220kV线路工程
安徽合肥铭传-华南城220kV线路工程
孔店-龙门500kV线路增容改造工程
游乐-南岗、游乐-湖光路T接方兴Ⅱ变电站110kV电缆线路工程
桐城-独秀π入双港变电站220kV线路工程
杨柳-南坪改接至双堆集牵引站220kV线路工程
合肥二电厂-彭郢π入长临河变电站220kV线路工程
合肥长临河-义兴220kV架空线路工程
陂塘-草庙乡牵引站220kV架空线路工程
安徽官山-涓桥I、II回π入池州二变500千伏线路工程
南坪-双堆集牵引站220kV线路工程
肥西-中心500kV线路工程架空部分
先锋-泉河π入安庆四变电站220kV线路工程
况楼-杨柳220kV线路工程
安庆四-涓桥500kV线路工程一般线路段
藕池-漆园π入杨柳变电站220kV线路工程
金牛-紫蓬500kV线路工程
合肥金牛-庐江π入庐江北变电站220KV线路工程
独秀-谭桥牵引站π入和平变电站220kV线路工程
龙门500kV变电站间隔扩建工程
安徽合肥下塘220kV变电站新建工程
芜湖潘坛220kV变电站新建工程
安徽滁州护桥220kV变电站2号主变扩建工程
岩歙220kV变电站新建工程
安徽淮北凌云220千伏变电站新建工程
六安汤池 110kV 变电站新建工程
白莲-邵岗π入尧塘变电站35kV架空线路工程
淮南至桐城高速公路淮南段500kV电力迁改工程
国网安徽电力营销服务计量用房
国网安徽亳州供电公司运检营销综合用房
安庆四500kV变电站新建工程建筑
安徽沙河变至原鹿变500kV双回线路开断接入阜四变工程
黄栗树-儒林π入堰陈变电站110kV线路工程
金上-湖北线路工程川12标
安徽阜阳薛桥-花园220kV线路改造工程
章塘-邰桥、石桥-邰桥π入万济变电站110kV线路工程
围屏-石桥π入万济变电站110kV线路工程
安庆-龙山π入安庆四变电站220kV线路工程
夏湖-华都改接入真源变电站110kV线路工程
蓼城-冯井π入尧塘变电站110kV线路工程
汤池-河棚35kV架空线路工程
埇桥-萧砀回500千伏线路工程
安徽官山-涓桥、回π入池州二变500千伏线路工程
众兴-草庙乡牵引站220kV架空线路工程
湖站1000千伏1号主变A相局放配合项目
肥西-繁昌、Ⅱ回500kV线路改造工程
宁芜铁扩能改造(安徽段)涉及500kV线路跨越宁芜铁路迁改工程
S334峨山路东延伸(沿江高速至芜宣高速)新建工程二期500kV电力迁改工程
芜湖抖音220kV线路涉500kV峨峰5914、峨廻5904线改造工程
包河10kV延安30与兴集18网架结构优化工程施工
国网安徽马鞍山供电公司500kV峨廻5904线#92等拉线杆塔改造工程
国网安徽合肥供电公司2024年500kV肥西变电站一键顺控系统完善提升
淮南芦集 220千伏变电站220千伏配电装置改造工程
国网安徽马鞍山供电公司220kV恒兴变电站220kV配电装置改造
和襄高速机电工程总承包项目500kV-1100kV特高压电力线路迁建工程
阜四500千伏变电站新建工程(建筑部分)
蚌埠孝仪220kV变电站新建工程
陕北~安徽±800千伏特高压直流输电工程受端换流站四通一平工程
无人机智能巡检技术实验室项目
国网安徽淮北供电公司500kV濉溪变电站1号主变5022电流互感器改造
况楼220kV变电站间隔扩建工程
国网北京检修公司2024年±500kV延庆换流站阀冷系统设备驻站
安庆武昌220kV变电站220kV江调间隔扩建工程
香涧-梨花π入固镇南牵引站220kV线路工程
安徽合肥杜岗Ⅱ220kV开关站新建工程
国网安徽合肥供电公司2024年220kV板桥变电站一键顺控系统完善提升
科学城-长岗回π入塘稍变电站110kV架空线路工程
牛草山风电场-仙河T接黄阳变电站110kV线路 工程
世袭庄园二期居配工程
谷岭220kV变电站220kV蕲城电厂、埇南间隔扩建工程
官塘-燕山π入孝仪变电站220kV线路工程
甘肃-浙江线路工程施工包1芜湖市无为市-芜湖市南陵县)
新河-建阳、明都-建阳π入红桥变电站220kV线路工程
霸王-厉阳T接金河口110kV线路工程
双港-独秀π入和平变电站220kV线路工程
程集-牛庄π入阜四变220千伏线路工程
合州换流站-文都500千伏线路工程
安庆四-涓桥500kV线路工程长江大跨越段
和平-邓村π入双港变电站220kV线路工程
安徽合肥包河区10kV王郢19开关网架结构优化工程施工
合肥二电厂-彭郢π入长临河变电站 220kV 线路工程
安徽合肥肥西-游乐π入华南城变220kV架空线路工程
安徽阜阳颍上县110kV半岗-润河35kV线路工程
游乐-南岗、游乐-湖光路T接方兴Ⅱ变电站110kV架空线路工程
合肥轨道7号线10kV杆线迁改工程
科学城-长岗双回T接空港改接塘稍变电站110kV架空线路工程
安徽蚌埠濠州220kV变电站220千伏大唐凤阳红心镇光伏间隔扩建工程(电气安装)
余桥-银山220kV线路工程
六庆城际铁路穿±500kV宜华线改造工程
魏岗-古井π入祝集110kV线路工程
灵泗500kV变电站新建工程
蚌埠大唐滁州电厂220kV送出工程
国网北京检修公司2024年±500kV延庆换流站直流主设备年度检修维护

25
api/utils.py Normal file
View File

@ -0,0 +1,25 @@
from enum import Enum
def load_standard_name(file_path:str):
try:
with open(file_path, 'r', encoding='utf-8') as file:
lines = [line.strip() for line in file if line.strip()]
return lines
except FileNotFoundError:
print(f"错误:文件 {file_path} 不存在")
raise FileNotFoundError(f"错误:文件 {file_path} 不存在")
except Exception as e:
print(f"读取文件时发生错误:{e}")
raise Exception(f"错误:文件 {file_path} 不存在")
class CheckResult(Enum):
NO_MATCH = 0 # 不符合检查条件
MATCH_FOUND = 1 # 匹配到了值
NEEDS_MORE_ROUNDS = 2 # 需要多轮
class StandardType(Enum):
#工程名检查
PROJECT_CHECK = 0
#项目名检查
PROGRAM_CHECK = 1

View File

@ -63,8 +63,8 @@ def preprocess_function(example, tokenizer):
# === 3. 加载 UIE 预训练模型 ===
model = ErnieForTokenClassification.from_pretrained("uie-base", num_classes=21) # 3 类 (O, B, I)
tokenizer = ErnieTokenizer.from_pretrained("uie-base")
model = ErnieForTokenClassification.from_pretrained(r"/mnt/d/weiweiwang/intention/models/uie-base", num_classes=21) # 3 类 (O, B, I)
tokenizer = ErnieTokenizer.from_pretrained(r"/mnt/d/weiweiwang/intention/models/uie-base")
# === 4. 加载数据集 ===
train_dataset = load_dataset("data/data_part1.json") # 训练数据集
@ -81,7 +81,7 @@ data_collator = DataCollatorForTokenClassification(tokenizer, padding=True)
# === 7. 训练参数 ===
training_args = TrainingArguments(
output_dir="./uie_ner",
output_dir="./output",
evaluation_strategy="epoch",
save_strategy="epoch",
per_device_train_batch_size=16, # 你的显存较大,可调整 batch_size