算法优化,切换到从redis获取标准化数据

This commit is contained in:
weiweiw 2025-04-24 13:55:49 +08:00
parent b80f824bf7
commit c911482a19
11 changed files with 3610 additions and 947 deletions

View File

@ -3,5 +3,4 @@ api_key = 'EMPTY'
model_name = 'qwen2.5-instruct'
redis_url = "redis://:Bonus@Redis123!@192.168.0.37:16379"
# redis_url = "redis://:Dszbns@Redis123!@10.138.55.50:16379"

View File

@ -1,11 +1,10 @@
# constants.py
SIMILARITY_VALUE = 75
#匹配工程名时,需要过滤掉的词汇
USELESS_PROJECT_WORDS = ["项目", "工程", "变电站", "线路", "变电","千伏" ,"换流站","公司","直流"]
#匹配工程名时,需要过滤掉的词汇,线路, "变电站","换流站","变电",","调试部分"
USELESS_PROJECT_WORDS = ["项目", "工程", "变电站", "线路", "变电","千伏" ,"换流站","公司","直流","部分","施工"]
# USELESS_PROJECT_WORDS = ["项目", "工程", "千伏" ,"公司","直流"]
#匹配公司名时,需要过滤掉的词汇
USELESS_COMPANY_WORDS = ["公司","有限","责任","工程"]
USELESS_COMPANY_WORDS = ["公司","有限","责任","工程","科技"]
COMPANYNAME_SHA = "顺安电网建设有限公司"
#日期
@ -24,7 +23,9 @@ PROJECT_DEPARTMENT = "projectDepartment"
PROJECT_MANAGER = "projectManager"
#分包商
SUBCONTRACTOR = "subcontractor"
#班组
#班组
TEAM_LEADER = "teamLeader"
#风险
RISK_LEVEL = "riskLevel"
#班组名称
TEAM_NAME = "teamName"

View File

@ -1,12 +1,11 @@
# globalData.py
import json
import time
import redis
from config import redis_url
class GlobalData:
# 数据字段
standard_company_program = {}
standard_company_name_list = []
@ -25,113 +24,74 @@ class GlobalData:
simply_to_standard_constractor_name_map = {}
pinyin_simply_to_standard_constractor_name_map = {}
@classmethod
def update_from_local(cls):
from utils import (
load_standard_data,
load_standard_name,
clean_useless_company_name,
clean_useless_project_name,
text_to_pinyin
)
# 公司数据
temp_standard_company_program = load_standard_data("./standard_data/standard_company_program.json")
if temp_standard_company_program != cls.standard_company_program:
cls.standard_company_program.clear()
cls.standard_company_program.update(temp_standard_company_program)
cls.standard_company_name_list.clear()
cls.standard_company_name_list.extend(list(cls.standard_company_program.keys()))
cls.simply_to_standard_company_name_map.clear()
cls.simply_to_standard_company_name_map.update({
clean_useless_company_name(kw): kw for kw in cls.standard_company_name_list
})
cls.pinyin_simply_to_standard_company_name_map.clear()
cls.pinyin_simply_to_standard_company_name_map.update({
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_company_name_list
})
# 工程名数据
temp_standard_project_name_list = load_standard_name('./standard_data/standard_project.txt')
if temp_standard_project_name_list != cls.standard_project_name_list:
cls.standard_project_name_list.clear()
cls.standard_project_name_list.extend(temp_standard_project_name_list)
cls.simply_to_standard_project_name_map.clear()
cls.simply_to_standard_project_name_map.update({
clean_useless_project_name(kw): kw for kw in cls.standard_project_name_list
})
cls.pinyin_simply_to_standard_project_name_map.clear()
cls.pinyin_simply_to_standard_project_name_map.update({
text_to_pinyin(clean_useless_project_name(kw)): kw for kw in cls.standard_project_name_list
})
# 建管单位数据
temp_standard_construct_name_list = load_standard_name('./standard_data/construct_unit.txt')
if temp_standard_construct_name_list != cls.standard_construct_name_list:
cls.standard_construct_name_list.clear()
cls.standard_construct_name_list.extend(temp_standard_construct_name_list)
cls.simply_to_standard_construct_name_map.clear()
cls.simply_to_standard_construct_name_map.update({
clean_useless_company_name(kw): kw for kw in cls.standard_construct_name_list
})
cls.pinyin_simply_to_standard_construct_name_map.clear()
cls.pinyin_simply_to_standard_construct_name_map.update({
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_construct_name_list
})
# 分包单位数据
temp_standard_constractor_name_list = load_standard_name('./standard_data/sub_contract.txt')
if temp_standard_constractor_name_list != cls.standard_constractor_name_list:
cls.standard_constractor_name_list.clear()
cls.standard_constractor_name_list.extend(temp_standard_constractor_name_list)
cls.simply_to_standard_constractor_name_map.clear()
cls.simply_to_standard_constractor_name_map.update({
clean_useless_company_name(kw): kw for kw in cls.standard_constractor_name_list
})
cls.pinyin_simply_to_standard_constractor_name_map.clear()
cls.pinyin_simply_to_standard_constractor_name_map.update({
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_constractor_name_list
})
print(f"✅ Data updated from local at {time.strftime('%Y-%m-%d %H:%M:%S')}")
standard_team_leader_name_list = []
simply_to_standard_team_leader_name_map = {}
pinyin_simply_to_standard_team_leader_name_map = {}
@classmethod
def update_from_redis(cls):
import sys
from utils import (
load_standard_data,
load_standard_name,
clean_useless_company_name,
clean_useless_project_name,
clean_useless_team_leader_name
)
#实施组织(分公司)和项目名
cls._update_company_program()
total_size = sys.getsizeof(GlobalData.standard_company_program) + sys.getsizeof(GlobalData.standard_company_name_list) + sys.getsizeof(GlobalData.simply_to_standard_company_name_map)+ sys.getsizeof(GlobalData.pinyin_simply_to_standard_company_name_map)
print(f"standard_company size: {total_size} bytes")
#工程名
cls._update_list_data('SBD_QUERY_DATA:PROJECT_NAME', './standard_data/standard_project.txt',
cls.standard_project_name_list, cls.simply_to_standard_project_name_map,
cls.pinyin_simply_to_standard_project_name_map, clean_useless_project_name)
print(f"工程名数量:{len(cls.standard_project_name_list)}")
#建管单位
cls._update_list_data('SBD_QUERY_DATA:CONSTRUCTION_UNIT', './standard_data/construct_unit.txt',
cls.standard_construct_name_list, cls.simply_to_standard_construct_name_map,
cls.pinyin_simply_to_standard_construct_name_map, clean_useless_company_name)
print(f"建管单位数量:{len(cls.standard_construct_name_list)}")
#分包单位
cls._update_list_data('SBD_QUERY_DATA:SUBCONTRACTOR', './standard_data/sub_contract.txt',
cls.standard_constractor_name_list, cls.simply_to_standard_constractor_name_map,
cls.pinyin_simply_to_standard_constractor_name_map, clean_useless_company_name)
print(f"分包单位数量:{len(cls.standard_constractor_name_list)}")
#班组名称
cls._update_list_data('SBD_QUERY_DATA:TEAM', './standard_data/team_leader.txt',
cls.standard_team_leader_name_list, cls.simply_to_standard_team_leader_name_map,
cls.pinyin_simply_to_standard_team_leader_name_map, clean_useless_team_leader_name)
print(f"班组名称数量:{len(cls.standard_team_leader_name_list)}")
@classmethod
def _update_company_program(cls):
from utils import (
load_standard_json_data,
save_dict_to_file,
clean_useless_company_name,
text_to_pinyin
)
# 公司与项目关系数据
try:
r = redis.from_url(redis_url, decode_responses=True)
json_str = r.get('SBD_QUERY_DATA:STANDARD_COMPANY_PROGRAM')
if json_str:
temp_data = json.loads(json_str)
save_dict_to_file(temp_data,"./standard_data/standard_company_program.json")
print("[Info] Loaded STANDARD_COMPANY_PROGRAM from Redis")
else:
raise ValueError("Redis key not found")
except Exception as e:
print(f"[Error] Error loading STANDARD_COMPANY_PROGRAM: {e}")
temp_data = load_standard_json_data("./standard_data/standard_company_program.json")
# 公司数据
# r = redis.Redis(host='192.168.0.37', port=16379, password = 'Bonus@Redis123!', decode_responses=True)
r = redis.from_url(redis_url, decode_responses=True)
json_str = r.get('SBD_QUERY_DATA:STANDARD_COMPANY_PROGRAM')
if json_str:
temp_standard_company_program = json.loads(json_str)
print(f"update_from_redis:temp_standard_project_name_list from redis")
else:
temp_standard_company_program = load_standard_data("./standard_data/standard_company_program.json")
if temp_standard_company_program != cls.standard_company_program:
if temp_data != cls.standard_company_program:
cls.standard_company_program.clear()
cls.standard_company_program.update(temp_standard_company_program)
cls.standard_company_program.update(temp_data)
cls.standard_company_name_list.clear()
cls.standard_company_name_list.extend(list(cls.standard_company_program.keys()))
cls.standard_company_name_list.extend(list(temp_data.keys()))
cls.simply_to_standard_company_name_map.clear()
cls.simply_to_standard_company_name_map.update({
@ -143,64 +103,42 @@ class GlobalData:
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_company_name_list
})
# 工程名数据
json_str = r.get('SBD_QUERY_DATA:PROJECT_NAME')
@classmethod
def _update_list_data(cls, redis_key, local_path, target_list, simple_map, pinyin_map, cleaner):
from utils import (
load_standard_name_list,
save_standard_name_list_to_file,
text_to_pinyin
)
try:
r = redis.from_url(redis_url, decode_responses=True)
json_str = r.get(redis_key)
except Exception as e:
print(f"[Error] Redis error on key '{redis_key}': {e}")
json_str = None
if json_str:
temp_standard_project_name_list = json.loads(json_str)
print(f"update_from_redis:temp_standard_project_name_list from redis")
try:
temp_list = json.loads(json_str)
save_standard_name_list_to_file(temp_list,local_path)
print(f"[Info] Loaded {redis_key} from Redis")
except json.JSONDecodeError as e:
print(f"[Warning] JSON decode error on key '{redis_key}': {e}")
temp_list = load_standard_name_list(local_path)
else:
temp_standard_project_name_list = load_standard_name('./standard_data/standard_project.txt')
print(f"[Info] Redis key '{redis_key}' not found. Loading from local file...")
temp_list = load_standard_name_list(local_path)
if temp_standard_project_name_list != cls.standard_project_name_list:
cls.standard_project_name_list.clear()
cls.standard_project_name_list.extend(temp_standard_project_name_list)
if temp_list != target_list:
target_list.clear()
target_list.extend(temp_list)
cls.simply_to_standard_project_name_map.clear()
cls.simply_to_standard_project_name_map.update({
clean_useless_project_name(kw): kw for kw in cls.standard_project_name_list
simple_map.clear()
simple_map.update({
cleaner(kw): kw for kw in temp_list
})
cls.pinyin_simply_to_standard_project_name_map.clear()
cls.pinyin_simply_to_standard_project_name_map.update({
text_to_pinyin(clean_useless_project_name(kw)): kw for kw in cls.standard_project_name_list
pinyin_map.clear()
pinyin_map.update({
text_to_pinyin(cleaner(kw)): kw for kw in temp_list
})
# 建管单位数据
temp_standard_construct_name_list = load_standard_name('./standard_data/construct_unit.txt')
if temp_standard_construct_name_list != cls.standard_construct_name_list:
cls.standard_construct_name_list.clear()
cls.standard_construct_name_list.extend(temp_standard_construct_name_list)
cls.simply_to_standard_construct_name_map.clear()
cls.simply_to_standard_construct_name_map.update({
clean_useless_company_name(kw): kw for kw in cls.standard_construct_name_list
})
cls.pinyin_simply_to_standard_construct_name_map.clear()
cls.pinyin_simply_to_standard_construct_name_map.update({
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_construct_name_list
})
# 分包单位数据
json_str = r.get('SBD_QUERY_DATA:SUBCONTRACTOR')
if json_str:
temp_standard_constractor_name_list = json.loads(json_str)
print(f"update_from_redis:temp_standard_constractor_name_list from redis")
else:
temp_standard_constractor_name_list = load_standard_name('./standard_data/sub_contract.txt')
if temp_standard_constractor_name_list != cls.standard_constractor_name_list:
cls.standard_constractor_name_list.clear()
cls.standard_constractor_name_list.extend(temp_standard_constractor_name_list)
cls.simply_to_standard_constractor_name_map.clear()
cls.simply_to_standard_constractor_name_map.update({
clean_useless_company_name(kw): kw for kw in cls.standard_constractor_name_list
})
cls.pinyin_simply_to_standard_constractor_name_map.clear()
cls.pinyin_simply_to_standard_constractor_name_map.update({
text_to_pinyin(clean_useless_company_name(kw)): kw for kw in cls.standard_constractor_name_list
})
print(f"✅ Data updated from local at {time.strftime('%Y-%m-%d %H:%M:%S')}")

View File

@ -1,24 +1,30 @@
import time
from flask import Flask, jsonify, request
from pydantic import BaseModel, Field
from werkzeug.exceptions import HTTPException
from typing import List
from pydantic import ValidationError
import time
from intentRecognition import IntentRecognition
from slotRecognition import SlotRecognition
from utils import CheckResult, check_standard_name_slot_probability, check_lost
from config import *
from globalData import GlobalData
from apscheduler.schedulers.background import BackgroundScheduler
# MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-22960"
# MODEL_UIE_PATH = R"../uie/output/checkpoint-22670"
MODEL_ERNIE_PATH = R"../ernie/output_temp/checkpoint-26250"
MODEL_UIE_PATH = R"../uie/output_/checkpoint-259600"
MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-22620"
MODEL_UIE_PATH = R"../uie/output/checkpoint-22320"
# 类别名称列表
labels = [
"天气查询", "互联网查询", "页面切换", "日计划数量查询", "周计划数量查询",
"日计划作业内容", "周计划作业内容", "施工人数", "作业考勤人数", "知识问答",
"通用对话", "作业面查询", "班组人数查询", "班组数查询", "作业面内容", "班组详情"
"通用对话", "作业面查询", "班组人数查询", "班组数查询", "作业面内容", "班组详情",
"工程进度查询"
]
# 标签映射
@ -47,12 +53,19 @@ intent_recognizer = IntentRecognition(MODEL_ERNIE_PATH, labels)
slot_recognizer = SlotRecognition(MODEL_UIE_PATH, label_map)
# 设置Flask应用
# update_data_from_local()
from globalData import GlobalData
GlobalData.update_from_local()
app = Flask(__name__)
def job():
print(f"✅ [Info] Executing update_from_redis...at {time.strftime('%Y-%m-%d %H:%M:%S')}")
GlobalData.update_from_redis()
job()
# 创建后台调度器
scheduler = BackgroundScheduler()
scheduler.add_job(job, 'cron', hour=3, minute=0) # 每天凌晨1点执行
# scheduler.add_job(job, 'cron', minute='*/5')
scheduler.start()
# 统一的异常处理函数
@app.errorhandler(Exception)
@ -162,6 +175,7 @@ def slot_reco():
return user_validation_error
# 调用 recognize 方法进行槽位识别
# entities = slot_recognizer.recognize(text)
entities, slot_probability = slot_recognizer.recognize_probability(text)
print(
f"槽位抽取后的实体:{entities},实体后的可能值:{slot_probability}",
@ -203,9 +217,10 @@ def agent():
# 先进行意图识别
predicted_label, predicted_probability, predicted_id = intent_recognizer.predict(query)
# 再进行槽位抽取
entities,slot_probability = slot_recognizer.recognize_probability(query)
entities, slot_probability = slot_recognizer.recognize_probability(query)
print(
f"第一轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},slot_probability:{slot_probability},message:{messages}",
f"第一轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},,slot_probability:{slot_probability},message:{messages}",
flush=True)
# 多轮
else:
@ -220,9 +235,10 @@ def agent():
"answer": {"int": predicted_id, "label": predicted_label, "probability": predicted_probability},
"finalQuery": res
})
# entities = slot_recognizer.recognize(res)
entities, slot_probability = slot_recognizer.recognize_probability(res)
print(
f"多轮意图识别后的槽位:槽位抽取后的实体:{entities},slot_probability:{slot_probability}",
f"多轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},slot_probability:{slot_probability},message:{messages}",
flush=True)
#必须槽位缺失检查
@ -239,11 +255,6 @@ def agent():
"code": 10001, "msg": "成功",
"answer": {"miss": information},
})
if result == CheckResult.NEEDS_MORE_ROUNDS:
return jsonify({
"code": 10001, "msg": "成功",
"answer": {"miss": information},
})
return jsonify({
"code": 200, "msg": "成功",
@ -260,22 +271,18 @@ def agent():
def extract_multi_chat(messages):
from openai import OpenAI
client = OpenAI(base_url=api_base_url, api_key=api_key)
latest_message = messages[-1] # 最后一条用户提问
if latest_message.role == "user":
latest_user_question = latest_message.content.strip()
time_prefixes = ["今天", "昨天", "本周", "下周", "明天", "今日"] # 可扩展的时间前缀列表
if any(latest_user_question.startswith(prefix) for prefix in time_prefixes):
history_messages = []
else:
history_messages = messages[:-1] # 除最后一条之外的历史记录
# 格式化对话历史
chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages])
latest_message = messages[-1]
latest_user_question = latest_message.content if latest_message.role == "user" else ""
time_prefixes = ["今天", "昨天", "本周", "下周", "明天", "今日"]
history_messages = [] if any(prefix in latest_user_question for prefix in time_prefixes) else messages[:-1]
print("len(history_messages):\n", len(history_messages))
oldest_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[:2]])
last_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[-2:]])
prompt = f'''
你是一个意图识别与补全助手你的任务是根据用户的最新问题判断是否需要补全如果不需要补全则原样返回用户的最新问题否则需要结合对话记录请你补用户的最新问题并只返回最终的完整问题请严格按照如下逻辑判断并执行
你是一个意图识别与补全助手你的任务是根据用户的最新问题判断是否需要补全如果不需要补全则原样返回用户的最新问题否则需要结合最新对话历史和最老对话历史补全用户的最新问题并只返回最终的完整问题请严格按照如下逻辑判断并执行
---
@ -299,37 +306,44 @@ def extract_multi_chat(messages):
- 用户最新问题今天绿雪莲塘工程有多少作业计划
- 最终提问均为 原句不变
第三步用户最新问题是否存在指代词 结合用户最新问题和对话记录进行补全
- 若用户最新问题问题中出现模糊表达具体是哪些项是哪两个作业计划分别是什么合肥中心变工程呢具体是哪20项结合上一个用户问题和上一个AI回复补全问题信息
第三步用户最新问题是否存在指代词 结合用户最新问题和最新对话历史进行补全
- 若用户最新问题问题中出现模糊表达具体是哪些项是哪两个作业计划分别是什么合肥中心变工程呢具体是哪20项只使用紧邻最新问题之前的用户问题和AI回复补全问题信息
- 示例1
- 用户最新问题具体的作业计划分别是什么
- 对话记录的最后一个用户问题今天送一分公司有多少项作业计划
- 对话记录的最后一个AI回答今天送电一分公司有21项作业计划
- 紧邻最新问题的对话历史的用户问题今天送一分公司有多少项作业计划
- 紧邻最新问题的对话历史的AI回答今天送电一分公司有21项作业计划
- 则最终提问应为
今天送电一分公司的21项作业计划分别是什么
- 示例2
- 用户最新问题具体的作业内容是什么
- 对话记录的最后一个用户问题今天送一分公司第一项目部有多少项作业计划
- 对话记录的最后一个AI回答今天送电一分公司第一项目管理部有21项作业计划
- 用户最新问题具体的作业内容是什么
- 最新对话历史的用户问题今天送一分公司第一项目部有多少项作业计划
- 最新对话历史的AI回答今天送电一分公司第一项目管理部有21项作业计划
- 则最终提问应为
今天送电一分公司第一项目管理部的21项作业计划分别是什么
第四步用户最新问题是否为序号指代第一个/第2个 用完整工程/项目/公司名替换补全
- 精确提取用户所指的序号第3个指第3个工程名公司名或项目部名
- 将该工程公司或项目部的完整名称包括括号中的编号提取出来
- **用完整名称替换掉用户上一个问题中出现的简称或模糊表达并保留用户问题中的其它部分原样不变如时间计划数内容不变**
- 用完整名称替换掉最新对话历史的用户问题中出现的简称或模糊表达
- 必须保留最新对话历史的用户问题中的所有其他关键信息包括但不限于项目部名称时间计划数内容如"进度情况""作业计划""作业内容"
- 示例1
- 用户最新问题:"一个" "第1"
- 对话记录的最后一个用户问题"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划""
- 对话记录的最后一个的AI回答列出多个工程名第1个是`检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)`
- 用户最新问题:"二个" "第2"
- 最新对话历史的用户问题"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划""
- 最新对话历史的AI回答你说的工程名可能是第一个检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)第二个:黄阳-仙河110kV线路工程(PROJ-2024-0047)请确认您要选择哪一个
- 则最终提问应为
`检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划`
`黄阳-仙河110kV线路工程(PROJ-2024-0047))今天有多少作业计划`
- 示例2
- 用户最新问题:"二个" "第2"
- 对话记录的最后一个用户问题"宏源电力建设公司第三项目部今天有多少项作业计划""
- 对话记录的最后一个AI回答列出多个分公司名第2个"安徽宏源电力建设有限公司(线路)"
- 用户最新问题:"2个" "第二"
- 紧最新对话历史的用户问题"请帮我查一下今天芦集变电站的进度情况"
- 最新对话历史的AI回答你说的工程名可能是第1个芦集-古沟π入潘集变电站220kV线路工程(PROJ-2024-0189)第二个淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265)请确认您要选择哪一个
- 则最终提问应为
"安徽宏源电力建设有限公司(线路)第三项目部今天有多少项作业计划"
"请帮我查一下今天淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265)的进度情况"
- 示例3新增关键保留示例
- 用户最新问题:"第2个"
- 最新对话历史的用户问题"宏源电力公司第三项目部今天有多少项作业计划"
- 最新对话历史的AI回答您说的实施组织名可能是,第1个安徽宏源电力建设有限公司(线路)第2个安徽宏源电力建设有限公司(变电),请选择哪一个
- 则最终提问应为
"安徽宏源电力建设有限公司(变电)第三项目部今天有多少项作业计划"
第五步输出最终问题
- 直接输出最终问题无解释无多余前缀或后缀
@ -337,8 +351,10 @@ def extract_multi_chat(messages):
---
对话记录
{chat_history}
最老对话历史:
{oldest_chat_history}
最新对话历史
{last_chat_history}
用户最新问题
{latest_user_question}
@ -349,8 +365,6 @@ def extract_multi_chat(messages):
{"role": "user", "content": prompt}
]
print(f"message:{message}")
response = client.chat.completions.create(
messages=message,
model=model_name,
@ -364,127 +378,7 @@ def extract_multi_chat(messages):
return res
#
# #
# test_cases = [
# ("送一分公司"),
# ("送二分公司"),
# ("变电分公司"),
# ("建筑分公司"),
# ("检修试验分公司"),
# ("宏源电力公司"),
# ("宏源电力限公司"),
# ("宏源电力限公司线路"),
# ("宏源电力限公司变电"),
# ("送一分"),
# ("送二分"),
# ("变电分"),
# ("建筑分"),
# ("检修试验分"),
# ("宏源电力"),
# ("红源电力"),
# ("宏源电力有限"),
# ("宏源电力限线路"),
# ("宏源电力限变电"),
# ]
#
# print(f"加权混合策略 分公司名匹配**********************")
# start = time.perf_counter()
# for item in test_cases:
# match_results = standardize_sub_company(item,simply_to_standard_company_name_map, pinyin_simply_to_standard_company_name_map,55,80)
# print(f"加权混合策略 分公司名匹配 输入: {item}-> 输出: {match_results}")
# end = time.perf_counter()
# print(f"加权混合策略 耗时: {end - start:.4f} 秒")
#
#
# #
# test_cases = [
# ("卢集"),
# ("芦集"),
# ("芦集变电站"),
# ("安庆四变电站"),
# ("锦绣变电站"),
# ("滁州护桥变电站"),
# ("合州换流站"),
# ("陕北合州换流站"),
# ("陕北安徽合州换流站"),
# ("金牛变电站"),
# ("香涧鹭岛工程"),
# ("延庆换流站"),
# ("国网延庆换流站"),
# ("国网北京延庆换流站"),
# ("陶楼广银线路工程"),
# ("紫蓬变电站"),
# ("宿州萧砀变电站"),
# ("冯井变电站"),
# ("富邦秋浦变电站"),
# ("包河玉龙变电站"),
#
# ("绿雪莲塘工程"),
# ("合肥循环园工程"),
# ("合肥长临河工程"),
# ("合肥中心变"),
# ("锁库变电站工程"),
# ("槽坊工程"),
#
# ("安庆四500kV变电站新建工程(PROJ-2024-0862)"),
# ("锦绣-常青π入中心变电站220kV架空线路工程(PROJ-2024-1206)"),
# ("渝北±800千伏换流站电气安装A包(调试部分)(PROJ-2024-1192)"),
# ("先锋-泉河π入安庆四变电站220kV线路工程(PROJ-2024-0834)"),
# ("安徽滁州护桥220kV变电站2号主变扩建工程(PROJ-2024-0821)"),
# ("合州士800千伏换流站电气安装A包(PROJ-2025-0056)"),
# ("卫田-陶楼T接首业变电站110kV电缆线路工程(PROJ-2024-1236)"),
# ("谯城(亳三)-希夷220kV线路工程(PROJ-2024-1205)"),
# ]
# print(f"去不重要词汇 工程名匹配******************************************")
# start = time.perf_counter()
# for item in test_cases:
# match_results = standardize_project_name(item, simply_to_standard_project_name_map,
# pinyin_simply_to_standard_project_name_map, 70, 90)
# print(f"工程名匹配 输入: {item}-> 输出: {match_results}")
# end = time.perf_counter()
# print(f"词集匹配 耗时: {end - start:.4f} 秒")
#
# print(f"项目名匹配******************************************")
# oral_program_name_list = [
# ("第1项目部"), # 期望返回所有"第三项目管理部"
# ("第2项目部"),
# ("第3项目部"),
# ("第4项目部"),
# ("第5项目部"),
# ("第6项目部"),
# ("第7项目部"),
# ("第8项目部"),
# ("第9项目部"),
# ("第10项目部"),
# ("第11项目部"),
# ("第12项目部"),
# ("第13项目部"),
# ("电缆班"),
# ("调试1队"),
# ("调试2队"),
# ("调试3队"),
# ("调试4队"),
# ("调试5队"),
# ("第一项目管理部"),
# ("第二项目管理部"),
# ("第五项目管理部"),
# ("第十一项目管理部(萧砀线路)"),
# ("第三项目管理部(张店线路)"),
# ("第三项目管理部(岳西线路)"),
# ("第五项目管理部(蚌埠)"),
# ("第三项目管理部(六安线路)"),
# ("第十一项目管理部(宿州线路)"),
# ("调试一队"),
# ("调试二队"),
# ("调试三队"),
# ("电缆班"),
# ]
#
# for company in standard_company_name_list:
# for program in oral_program_name_list:
# match_results = standardize_projectDepartment(company, program, standard_company_program, high_score=90)
# print(f"加权混合策略 项目部名称 输入: 公司:{company},项目部:{program}-> 输出: {match_results}")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=18074, debug=True)
# 启动时立即执行一次
app.run(host='0.0.0.0', port=18074, debug=False)

View File

@ -1,19 +1,21 @@
import time
from flask import Flask, jsonify, request
from pydantic import BaseModel, Field
from werkzeug.exceptions import HTTPException
from typing import List
from pydantic import ValidationError
import time
from intentRecognition import IntentRecognition
from slotRecognition import SlotRecognition
from utils import CheckResult, check_standard_name_slot_probability, check_lost, standardize_sub_company, \
standardize_project_name, standardize_projectDepartment
from utils import CheckResult, check_standard_name_slot_probability, check_lost
from config import *
from globalData import GlobalData
from apscheduler.schedulers.background import BackgroundScheduler
MODEL_ERNIE_PATH = R"../ernie/output/checkpoint-22960"
MODEL_UIE_PATH = R"../uie/output/checkpoint-22670"
MODEL_ERNIE_PATH = R"../ernie/output_temp/checkpoint-22960"
MODEL_UIE_PATH = R"../uie/output_temp/checkpoint-22670"
# 类别名称列表
labels = [
"天气查询", "互联网查询", "页面切换", "日计划数量查询", "周计划数量查询",
@ -41,7 +43,6 @@ label_map = {
14: 'B-constructionArea', 28: 'I-constructionArea',
}
# 初始化工具类
intent_recognizer = IntentRecognition(MODEL_ERNIE_PATH, labels)
@ -49,12 +50,20 @@ intent_recognizer = IntentRecognition(MODEL_ERNIE_PATH, labels)
slot_recognizer = SlotRecognition(MODEL_UIE_PATH, label_map)
# 设置Flask应用
from globalData import GlobalData
GlobalData.update_from_local()
# GlobalData.update_from_redis()
app = Flask(__name__)
def job():
print(f"✅ [Info] Executing update_from_redis...at {time.strftime('%Y-%m-%d %H:%M:%S')}")
GlobalData.update_from_redis()
job()
# 创建后台调度器
scheduler = BackgroundScheduler()
# scheduler.add_job(job, 'cron', hour=1, minute=0) # 每天凌晨1点执行
scheduler.add_job(job, 'cron', minute='*/5')
scheduler.start()
# 统一的异常处理函数
@app.errorhandler(Exception)
def handle_exception(e):
@ -164,7 +173,7 @@ def slot_reco():
# 调用 recognize 方法进行槽位识别
# entities = slot_recognizer.recognize(text)
entities,slot_probability = slot_recognizer.recognize_probability(text)
entities, slot_probability = slot_recognizer.recognize_probability(text)
print(
f"槽位抽取后的实体:{entities},实体后的可能值:{slot_probability}",
flush=True)
@ -224,7 +233,7 @@ def agent():
"finalQuery": res
})
# entities = slot_recognizer.recognize(res)
entities,slot_probability = slot_recognizer.recognize_probability(res)
entities, slot_probability = slot_recognizer.recognize_probability(res)
print(
f"多轮意图识别后的label:{predicted_label}, id:{predicted_id},槽位抽取后的实体:{entities},slot_probability:{slot_probability},message:{messages}",
flush=True)
@ -259,22 +268,18 @@ def agent():
def extract_multi_chat(messages):
from openai import OpenAI
client = OpenAI(base_url=api_base_url, api_key=api_key)
latest_message = messages[-1] # 最后一条用户提问
if latest_message.role == "user":
latest_user_question = latest_message.content.strip()
time_prefixes = ["今天", "昨天", "本周", "下周", "明天", "今日"] # 可扩展的时间前缀列表
if any(latest_user_question.startswith(prefix) for prefix in time_prefixes):
history_messages = []
else:
history_messages = messages[:-1] # 除最后一条之外的历史记录
# 格式化对话历史
chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages])
latest_message = messages[-1]
latest_user_question = latest_message.content if latest_message.role == "user" else ""
time_prefixes = ["今天", "昨天", "本周", "下周", "明天", "今日"]
history_messages = [] if any(prefix in latest_user_question for prefix in time_prefixes) else messages[:-1]
print("len(history_messages):\n", len(history_messages))
oldest_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[:2]])
last_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[-2:]])
prompt = f'''
你是一个意图识别与补全助手你的任务是根据用户的最新问题判断是否需要补全如果不需要补全则原样返回用户的最新问题否则需要结合对话记录请你补用户的最新问题并只返回最终的完整问题请严格按照如下逻辑判断并执行
你是一个意图识别与补全助手你的任务是根据用户的最新问题判断是否需要补全如果不需要补全则原样返回用户的最新问题否则需要结合最新对话历史和最老对话历史补全用户的最新问题并只返回最终的完整问题请严格按照如下逻辑判断并执行
---
@ -298,37 +303,44 @@ def extract_multi_chat(messages):
- 用户最新问题今天绿雪莲塘工程有多少作业计划
- 最终提问均为 原句不变
第三步用户最新问题是否存在指代词 结合用户最新问题和对话记录进行补全
- 若用户最新问题问题中出现模糊表达具体是哪些项是哪两个作业计划分别是什么合肥中心变工程呢具体是哪20项结合上一个用户问题和上一个AI回复补全问题信息
第三步用户最新问题是否存在指代词 结合用户最新问题和最新对话历史进行补全
- 若用户最新问题问题中出现模糊表达具体是哪些项是哪两个作业计划分别是什么合肥中心变工程呢具体是哪20项只使用紧邻最新问题之前的用户问题和AI回复补全问题信息
- 示例1
- 用户最新问题具体的作业计划分别是什么
- 对话记录的最后一个用户问题今天送一分公司有多少项作业计划
- 对话记录的最后一个AI回答今天送电一分公司有21项作业计划
- 紧邻最新问题的对话历史的用户问题今天送一分公司有多少项作业计划
- 紧邻最新问题的对话历史的AI回答今天送电一分公司有21项作业计划
- 则最终提问应为
今天送电一分公司的21项作业计划分别是什么
- 示例2
- 用户最新问题具体的作业内容是什么
- 对话记录的最后一个用户问题今天送一分公司第一项目部有多少项作业计划
- 对话记录的最后一个AI回答今天送电一分公司第一项目管理部有21项作业计划
- 用户最新问题具体的作业内容是什么
- 最新对话历史的用户问题今天送一分公司第一项目部有多少项作业计划
- 最新对话历史的AI回答今天送电一分公司第一项目管理部有21项作业计划
- 则最终提问应为
今天送电一分公司第一项目管理部的21项作业计划分别是什么
第四步用户最新问题是否为序号指代第一个/第2个 用完整工程/项目/公司名替换补全
- 精确提取用户所指的序号第3个指第3个工程名公司名或项目部名
- 将该工程公司或项目部的完整名称包括括号中的编号提取出来
- **用完整名称替换掉用户上一个问题中出现的简称或模糊表达并保留用户问题中的其它部分原样不变如时间计划数内容如进度情况作业计划作业内容不变**
- 用完整名称替换掉最新对话历史的用户问题中出现的简称或模糊表达
- 必须保留最新对话历史的用户问题中的所有其他关键信息包括但不限于项目部名称时间计划数内容如"进度情况""作业计划""作业内容"
- 示例1
- 用户最新问题:"一个" "第1"
- 对话记录的最后一个用户问题"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划""
- 对话记录的最后一个的AI回答列出多个工程名第1个是`检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)`
- 用户最新问题:"二个" "第2"
- 最新对话历史的用户问题"2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划""
- 最新对话历史的AI回答你说的工程名可能是第一个检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)第二个:黄阳-仙河110kV线路工程(PROJ-2024-0047)请确认您要选择哪一个
- 则最终提问应为
`检修公司调相机一二次设备检修维护和改造服务框架-2025年南苑调相机检修(PROJ-2023-0179)今天有多少作业计划`
`黄阳-仙河110kV线路工程(PROJ-2024-0047))今天有多少作业计划`
- 示例2
- 用户最新问题:"一个" "第1"
- 对话记录的最后一个用户问题"请帮我查一下今天芦集变电站的进度情况"
- 对话记录的最后一个AI回答列出多个工程名第1个"芦集-古沟π入潘集变电站220kV线路工程(PROJ-2024-0189)"
- 用户最新问题:"2个" "第二"
- 紧最新对话历史的用户问题"请帮我查一下今天芦集变电站的进度情况"
- 最新对话历史的AI回答你说的工程名可能是第1个芦集-古沟π入潘集变电站220kV线路工程(PROJ-2024-0189)第二个淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265)请确认您要选择哪一个
- 则最终提问应为
"请帮我查一下今天芦集-古沟π入潘集变电站220kV线路工程(PROJ-2024-0189)的进度情况"
"请帮我查一下今天淮南芦集220千伏变电站220千伏配电装置改造工程(PROJ-2024-0265)的进度情况"
- 示例3新增关键保留示例
- 用户最新问题:"第2个"
- 最新对话历史的用户问题"宏源电力公司第三项目部今天有多少项作业计划"
- 最新对话历史的AI回答您说的实施组织名可能是,第1个安徽宏源电力建设有限公司(线路)第2个安徽宏源电力建设有限公司(变电),请选择哪一个
- 则最终提问应为
"安徽宏源电力建设有限公司(变电)第三项目部今天有多少项作业计划"
第五步输出最终问题
- 直接输出最终问题无解释无多余前缀或后缀
@ -336,8 +348,10 @@ def extract_multi_chat(messages):
---
对话记录
{chat_history}
最老对话历史:
{oldest_chat_history}
最新对话历史
{last_chat_history}
用户最新问题
{latest_user_question}
@ -348,8 +362,6 @@ def extract_multi_chat(messages):
{"role": "user", "content": prompt}
]
print(f"message:{message}")
response = client.chat.completions.create(
messages=message,
model=model_name,
@ -363,238 +375,7 @@ def extract_multi_chat(messages):
return res
#标准化分公司名,工程名,项目名等
# def check_standard_name_slot(int_res, slot) -> tuple:
# intention_list = {3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15}
# if int_res not in intention_list:
# return CheckResult.NO_MATCH, ""
#
# #项目名 当项目名存在时需要一定存在分公司(实施组织)名
# if PROJECT_DEPARTMENT in slot:
# if IMPLEMENTATION_ORG not in slot:
# return CheckResult.NEEDS_MORE_ROUNDS, "请补充该项目部所属的分公司名称"
#
# #工程名和分公司名和项目名标准化
# for key, value in slot.items():
# if key == PROJECT_NAME:
# print(f"check_standard_name_slot 原始工程名 : {slot[PROJECT_NAME]}")
# match_results = standardize_project_name(value, simply_to_standard_project_name_map,
# pinyin_simply_to_standard_project_name_map, 70, 90)
# print(f"check_standard_name_slot 匹配后工程名 result:{match_results}", flush=True)
# if match_results and len(match_results) == 1:
# slot[key] = match_results[0]
# else:
# prompt = generate_project_prompt(match_results, original_name=slot[PROJECT_NAME], type="工程名")
# return CheckResult.NEEDS_MORE_ROUNDS, prompt
#
# if key == IMPLEMENTATION_ORG and slot[key] != "公司":
# print(f"check_standard_name_slot 原始分公司名 : {slot[IMPLEMENTATION_ORG]}")
# match_results = standardize_sub_company(value, simply_to_standard_company_name_map,
# pinyin_simply_to_standard_company_name_map, 55, 80)
# print(f"check_standard_name_slot 匹配后分公司名: result:{match_results}", flush=True)
# if match_results and len(match_results) == 1:
# slot[key] = match_results[0]
# else:
# prompt = generate_project_prompt(match_results, original_name=slot[IMPLEMENTATION_ORG], type="分公司名")
# return CheckResult.NEEDS_MORE_ROUNDS, prompt
#
# if key == PROJECT_DEPARTMENT:
# print(f"check_standard_name_slot 原始项目部名 : {slot[PROJECT_DEPARTMENT]}")
# match_results = standardize_projectDepartment(slot[IMPLEMENTATION_ORG], value, standard_company_program,
# high_score=90)
# print(f"check_standard_name_slot 匹配后项目部名: result:{match_results}", flush=True)
# if match_results and len(match_results) == 1:
# slot[key] = match_results[0]
# else:
# prompt = generate_project_prompt(match_results, original_name=slot[PROJECT_DEPARTMENT], type="项目名")
# return CheckResult.NEEDS_MORE_ROUNDS, prompt
# if key == RISK_LEVEL:
# if slot[RISK_LEVEL] not in ["2级", "3级", "4级", "5级"] and slot[RISK_LEVEL] not in ["二级", "三级", "四级",
# "五级"]:
# return CheckResult.NEEDS_MORE_ROUNDS, "您查询的风险等级在系统中未找到,请确认风险等级后再次提问"
#
# return CheckResult.NO_MATCH, ""
#
# test_cases = [
# ("送一分公司"),
# ("送二分公司"),
# ("变电分公司"),
# ("建筑分公司"),
# ("检修试验分公司"),
# ("宏源电力公司"),
# ("宏源电力限公司"),
# ("宏源电力限公司线路"),
# ("宏源电力限公司变电"),
# ("送一分"),
# ("送二分"),
# ("变电分"),
# ("建筑分"),
# ("检修试验分"),
# ("宏源电力"),
# ("红源电力"),
# ("宏源电力有限"),
# ("宏源电力限线路"),
# ("宏源电力限变电"),
# ]
#
# print(f"加权混合策略 分公司名匹配**********************")
# start = time.perf_counter()
# for item in test_cases:
# match_results = standardize_sub_company(item,GlobalData.simply_to_standard_company_name_map, GlobalData.pinyin_simply_to_standard_company_name_map,70,90)
# print(f"加权混合策略 分公司名匹配 输入: {item}-> 输出: {match_results}")
# end = time.perf_counter()
# print(f"加权混合策略 耗时: {end - start:.4f} 秒")
#
#
#
# test_cases = [
# ("合肥供电公司"),
# ("淮北供电公司"),
# ("六安市城郊供电公司"),
# ]
#
# print(f"加权混合策略 建管单位名匹配**********************")
# start = time.perf_counter()
# for item in test_cases:
# match_results = standardize_sub_company(item,GlobalData.simply_to_standard_construct_name_map, GlobalData.pinyin_simply_to_standard_construct_name_map,70,90)
# print(f"加权混合策略 建管单位名匹配 输入: {item}-> 输出: {match_results}")
#
# print(f"加权混合策略,分公司名匹配**********************")
# for item in test_cases:
# match_results = standardize_sub_company(item,GlobalData.simply_to_standard_company_name_map, GlobalData.pinyin_simply_to_standard_company_name_map,70,90)
# print(f"加权混合策略 分公司名匹配 输入: {item}-> 输出: {match_results}")
# end = time.perf_counter()
# print(f"加权混合策略 耗时: {end - start:.4f} 秒")
#
#
# #
# test_cases = [
# ("卢集"),
# ("芦集"),
# ("芦集变电站"),
# ("安庆四变电站"),
# ("锦绣变电站"),
# ("滁州护桥变电站"),
# ("合州换流站"),
# ("陕北合州换流站"),
# ("陕北安徽合州换流站"),
# ("金牛变电站"),
# ("香涧鹭岛工程"),
# ("延庆换流站"),
# ("国网延庆换流站"),
# ("国网北京延庆换流站"),
# ("陶楼广银线路工程"),
# ("紫蓬变电站"),
# ("宿州萧砀变电站"),
# ("冯井变电站"),
# ("富邦秋浦变电站"),
# ("包河玉龙变电站"),
#
# ("绿雪莲塘工程"),
# ("合肥循环园工程"),
# ("合肥长临河工程"),
# ("合肥中心变"),
# ("锁库变电站工程"),
# ("槽坊工程"),
#
# ("安庆四500kV变电站新建工程(PROJ-2024-0862)"),
# ("锦绣-常青π入中心变电站220kV架空线路工程(PROJ-2024-1206)"),
# ("渝北±800千伏换流站电气安装A包(调试部分)(PROJ-2024-1192)"),
# ("先锋-泉河π入安庆四变电站220kV线路工程(PROJ-2024-0834)"),
# ("安徽滁州护桥220kV变电站2号主变扩建工程(PROJ-2024-0821)"),
# ("合州士800千伏换流站电气安装A包(PROJ-2025-0056)"),
# ("卫田-陶楼T接首业变电站110kV电缆线路工程(PROJ-2024-1236)"),
# ("谯城(亳三)-希夷220kV线路工程(PROJ-2024-1205)"),
# ]
# print(f"去不重要词汇 工程名匹配******************************************")
# start = time.perf_counter()
# for item in test_cases:
# match_results = standardize_project_name(item, GlobalData.simply_to_standard_project_name_map,
# GlobalData.pinyin_simply_to_standard_project_name_map, 70, 90)
# print(f"工程名匹配 输入: {item}-> 输出: {match_results}")
# end = time.perf_counter()
# print(f"词集匹配 耗时: {end - start:.4f} 秒")
#
# print(f"项目名匹配******************************************")
# oral_program_name_list = [
# ("第1项目部"), # 期望返回所有"第三项目管理部"
# ("第2项目部"),
# ("第3项目部"),
# ("第4项目部"),
# ("第5项目部"),
# ("第6项目部"),
# ("第7项目部"),
# ("第8项目部"),
# ("第9项目部"),
# ("第10项目部"),
# ("第11项目部"),
# ("第12项目部"),
# ("第13项目部"),
# ("电缆班"),
# ("调试1队"),
# ("调试2队"),
# ("调试3队"),
# ("调试4队"),
# ("调试5队"),
# ("第一项目管理部"),
# ("第二项目管理部"),
# ("第五项目管理部"),
# ("第十一项目管理部(萧砀线路)"),
# ("第三项目管理部(张店线路)"),
# ("第三项目管理部(岳西线路)"),
# ("第五项目管理部(蚌埠)"),
# ("第三项目管理部(六安线路)"),
# ("第十一项目管理部(宿州线路)"),
# ("调试一队"),
# ("调试二队"),
# ("调试三队"),
# ("电缆班"),
# ]
#
# for company in GlobalData.standard_company_name_list:
# for program in oral_program_name_list:
# match_results = standardize_projectDepartment(company, program, GlobalData.standard_company_program, high_score=90)
# print(f"加权混合策略 项目部名称 输入: 公司:{company},项目部:{program}-> 输出: {match_results}")
# slot_list = [{"constructionUnit": "合肥供电公司"},
# {
# "date": "今天",
# "constructionUnit": "芜湖供电公司"
# },
# {
# "date": "今天",
# "implementationOrganization": "送电一分公司"
# },
# {
# "date": "今天",
# "subcontractor": "百瑞建设发展有限公司"
# },
# {
# "date": "今天",
# "subcontractor": "安徽宝德电力建设工程有限"
# }]
# slot_list = [{"implementationOrganization": "合肥供电公司"},
# {
# "date": "今天",
# "implementationOrganization": "芜湖供电公司"
# },
# {
# "date": "今天",
# "constructionUnit": "送电一分公司"
# },
# {
# "date": "今天",
# "constructionUnit": "百瑞建设发展有限公司"
# },
# {
# "date": "今天",
# "constructionUnit": "安徽宝德电力建设工程有限"
# }]
# for slot in slot_list:
# match_results = check_standard_name_slot_probability(12, slot)
# print(f"加权混合策略 项目部名称 输入: 原始槽位:{slot},输出: {match_results}")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=18073, debug=True)
# 启动时立即执行一次
app.run(host='0.0.0.0', port=18073, debug=False)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
安徽创成建筑安装有限公司
上海兴鸿建设工程有限公司
上海新煜建设集团有限公司
上煜建设(河南)有限公司
中一建设工程有限公司
中叶消防技术有限公司
中国核工业芜湖基础工程有限公司
中国能源建设集团安徽省电力设计院有限公司
中安华力建设集团有限公司
中州建设有限公司
作业班组管理中心
军顶城建集团有限公司
南京消防器材股份有限公司
南京蜀广岳建设工程有限公司
合肥丰泰建筑安装工程有限公司
合肥光信科技发展有限公司
合肥同昌防水防腐工程有限公司
合肥宏赢电力工程有限公司
合肥工大地基工程有限公司
合肥工大岩土工程有限公司
合肥巨力电力安装有限公司
合肥市王氏脚手架有限公司
合肥市睿电电气技术咨询服务有限责任公司
合肥市胜峰建筑安装有限公司
合肥新宇电力设备安装有限公司
合肥科大立安安全技术有限责任公司
合肥长原消防工程有限责任公司
合肥香馨建设集团有限公司
四川中宏天佑建设工程有限公司
四川华东电气集团有限公司
四川民安易润建设工程有限公司
四川润广建设有限公司
四川省南充市水电工程有限公司
四川省岳池县石垭建安总公司
四川省岳池电力建设总公司
四川省岳池送变电工程公司
四川省津华电力工程有限公司
国皖电力有限公司
安庆横江集团有限责任公司
安徽上川建设工程有限公司
安徽东明电力工程有限公司
安徽东甲电力工程有限公司
安徽中创电力建设工程有限公司
安徽中友电力工程有限公司
安徽中源共创电力工程有限公司
安徽中踔建设工程有限公司
安徽中隐建设有限公司
安徽丰临观泰建设工程有限公司
安徽乾坤电力工程有限公司
安徽京硚建设有限公司
安徽亿源电力工程有限公司
安徽亿甲建筑工程有限公司
安徽众安智诚电力科技有限公司
安徽众联电力建设有限公司
安徽优越电力建设有限公司
安徽光远电力安装工程有限公司
安徽六建建设集团有限公司
安徽凌一装饰设计工程有限公司
安徽凌慧信息科技有限公司
安徽凯鸿电力工程有限公司
安徽创兴电力工程有限公司
安徽创盛建设工程有限公司
安徽别颂建设工程有限公司
安徽劦力建筑装饰有限责任公司
安徽勤志消防机电工程有限公司
安徽华腾建筑安装工程有限公司
安徽合一城乡建设有限公司
安徽唐盛建筑工程有限公司
安徽嘉昂建设工程有限公司
安徽国盟电力科技有限公司
安徽国耀电力建设有限公司
安徽国腾电力工程有限公司
安徽国通电力建设有限公司
安徽国鑫电力工程有限公司
安徽圣宸建设工程有限公司
安徽城阳建设工程有限公司
安徽大信电力建设有限公司
安徽天力元电力科技发展有限公司
安徽天晟建设工程有限公司
安徽天顺电力工程有限公司
安徽宏实电力工程有限公司
安徽宏途能源建设工程有限公司
安徽宜电建设工程有限公司
安徽宝德电力建设工程有限公司
安徽寰宇装饰工程有限公司
安徽展图电力建设有限公司
安徽岩土工程有限责任公司
安徽岩土钻凿工程有限责任公司
安徽巢能钢结构有限公司
安徽巨昌电力工程有限公司
安徽常青建设集团有限公司
安徽广能电力建设有限公司
安徽得众电力安装工程有限公司
安徽德济建筑工程有限公司
安徽怀电能源科技有限公司
安徽恒烁建设有限公司
安徽恒玖建设工程有限公司
安徽恒达电力有限公司
安徽恺戈建设工程有限公司
安徽振源电力工程有限公司
安徽敬畏建设工程有限公司
安徽新友建设工程有限公司
安徽新辰消防工程有限公司
安徽新辰电力工程有限公司
安徽星联建筑安装有限公司
安徽晨皖电力工程有限公司
安徽林凡电力工程有限公司
安徽梅龙建设集团有限公司
安徽森度科技有限公司
安徽武翔电力工程有限公司
安徽永昌电力安装有限公司
安徽汇景电力工程有限公司
安徽汇泰建设工程有限公司
安徽汇良建设工程有限公司
安徽泓源电力建设有限公司
安徽泰央建设有限责任公司
安徽泰宇建筑有限公司
安徽津利电力发展有限公司
安徽派河建设工程有限公司
安徽海仝建筑工程有限公司
安徽消安消防工程有限公司
安徽润森电力工程有限公司
安徽淮宿建设工程有限公司
安徽淮润消防工程有限公司
安徽港好江南生态环境科技有限公司
安徽琼源建设工程有限公司
安徽瑞华电气有限公司
安徽申能建设工程有限公司
安徽百瑞建设发展有限公司
安徽盈信消防安全工程有限公司
安徽盛琛电力工程有限公司
安徽盛远电力工程有限公司
安徽省九鑫机械有限公司
安徽省南苑装饰工程有限公司
安徽省国汇建设工程有限公司
安徽省宜成电力安装工程有限责任公司
安徽省振兴建筑集团工程有限公司
安徽省振帆装饰有限公司
安徽省新利达建筑安装工程有限公司
安徽省泽吉电力工程有限公司
安徽省消防工程有限公司
安徽省益业消防工程有限公司
安徽省金牛建筑安装工程有限公司
安徽省鸿钢建设发展有限公司
安徽省鼎天电力工程有限责任公司
安徽省鼎立装饰工程有限公司
安徽硕昌电力工程有限公司
安徽祁兴建筑劳务有限公司
安徽科建防水防腐有限公司
安徽索峰电力工程有限公司
安徽联杰电力工程有限公司
安徽致多鑫建设工程有限公司
安徽苏亚建设集团有限公司
安徽荣厦建筑工程有限公司
安徽蓬冉建筑装饰工程有限公司
安徽路洋建设工程有限公司
安徽远宏电力工程有限公司
安徽送变电工程有限公司机具(物流)分公司
安徽金帛建设工程有限公司
安徽金鼎机械租赁有限公司
安徽钜强电力工程有限公司
安徽铭远电力工程有限公司
安徽锦拓电气工程有限公司
安徽长征电力建设有限公司
安徽雅丽建设集团有限公司
安徽顺全电力工程有限公司
安徽顺安电网建设有限公司
安徽鹏翔电力工程有限公司
安徽鼎信建设发展有限公司
安徽龙晟建筑工程有限责任公司
安徽龙脉电力建设有限公司
山东方智电力技术有限公司
山东鸿华建筑安装工程有限公司
广东金煜建设工程有限公司
建蓝能源投资发展有限公司
开封恒固基础工程有限公司
徐州市硕航建筑安装工程有限公司
徐州迪硕建设有限公司
扬中市富能电力线路搭建有限公司
无锡市锡山华能线路搭设脚手架有限公司
武汉久林电力建设有限公司
武汉永坚智城建设有限公司
汉唐电力建设有限公司
江苏九源电力工程有限公司
江苏沪港装饰集团有限公司
江西省富煌钢构有限公司
池州天宇电力安装工程有限责任公司
河南佩勋建筑工程有限公司
河南新丰源送变电工程有限公司
浙江大华建设集团有限公司
浙江安信电力建设有限公司
浙江慕盛建设有限公司
淮北精创新能源科技有限公司
淮南市超越电气安装有限责任公司
湖北东谷电力工程有限公司
湖北广元岩土工程有限公司
湖北湘电建设工程有限公司
湖南娄湘电力建设有限公司
湖南现代德雷工程有限公司
湖南金森电力建设集团有限公司
湘潭潭州电力建设有限公司
溧阳市宜源电力工程有限公司
滁州市东来建筑工程有限公司
滁州瑞源电力工程有限公司
滁州谛辰建筑工程有限公司
濮阳市三源建设工程有限公司
盐城市苏厦建设集团有限公司
福建文港建设工程有限公司
绿都建筑装饰集团有限公司
美华建设有限公司
芜湖丰华建筑安装工程有限公司
芜湖冉电电力安装工程有限责任公司
芜湖市四建建筑工程有限责任公司
芜湖市湾里建筑安装有限责任公司
芜湖梦泰建筑安装有限公司
西格码电气股份有限公司
通州建总集团有限公司
铜陵市明宇电力工程有限公司
陕西颐万建设工程有限公司
鸿泰电力集团有限公司

View File

@ -0,0 +1,463 @@
王斌班组
韩志龙班组
李长军班组
杜修均班组
倪阳阳班组
蜂生忠班组
刘雨豪班组
李彦月班组
姚帅班组
田青海班组
陈遵义班组
马新欣班组
叶宇豪班组
陈军班组
徐臻班组
周华平班组
郝军彪班组
齐中文班组
黄金涛班组
宋洪标班组
文加立班组
温家干班组
黄多银班组
荚志生班组
贺开军班组
张明义班组
龚艳振班组
董伟班组
王治国班组
周可富班组
乔富林班组
蒋毅班组
曾庆飞班组
范文立班组
何胜伍班组
李章贵班组
吴义新班组
郑云龙班组
徐钦文班组
张江福班组
盛平班组
储友健班组
熊宗书班组
李光明班组
朱明雷班组
耿兴海班组
王威班组
张小斌班组
徐基山班组
简党伟班组
何光勇班组
孙守雨班组
王文旭班组
何伟威班组
杨红州班组
吴绍义班组
郑兴勇班组
杨燕班组
杨世忠班组
李名洋班组
何军班组
侯二跃班组
李甫仰班组
庞宗颖班组
唐龙遂班组
鲁成明班组
全炳仲班组
谷伟班组
周山聪班组
熊杏红班组
伍海均班组
姜伟班组
周长杰班组
蔡应生班组
王庆贤班组
郜东明班组
李洋班组
吴子良班组
尤富平班组
黄玉林班组
夏则微班组
王胜芳班组
解为锁班组
王玉春班组
张素标班组
周波娃班组
赵鹏班组
伍勇维班组
窦宏兴班组
蔡劲松班组
胡紫鹏班组
岳云峰班组
张军伟班组
苏为地班组
李连喜班组
李泽升班组
洪万超班组
孙泽栋班组
罗杰班组
栾强班组
杨旺胜班组
李超班组
刘祥班组
蔡道平班组
汪吉祥班组
徐朝军班组
汪自存班组
徐本家班组
任培培班组
陈兰荣班组
宋长明班组
王龙班组
孙嘉庆班组
孙荣杰班组
董志才班组
李运海班组
齐伦班组
胡彬班组
邓路青班组
王占尧班组
王正东班组
杨笑峰班组
陈天一班组
陈中林班组
李齐班组
宫清富班组
孔德中班组
周名保班组
王书民班组
赵凌宇班组
詹廷军班组
徐蒙蒙班组
杨飞班组
翟虫付班组
孔得海班组
刘东明班组
孙春冬班组
范乃民班组
唐昌国班组
古明国班组
罗来正班组
何吕班组
李安强班组
周鹏班组
徐江林班组
侯本银班组
石红涛班组
李聪聪班组
罗泽齐班组
张玉伟班组
杨桥班组
黄辉班组
胡梦林班组
赵锋班组
刘告发班组
余火焰班组
于国清班组
邓君班组
李赛北班组
何东洋班组
古伟班组
叶从进班组
席胜利班组
孔永高班组
马祖普班组
温彪班组
王宏松班组
叶结锋班组
张乃仓班组
葛斌班组
王亮班组
方勇勇班组
徐兴才班组
蔡大羊班组
乔帅兵班组
刘荣君班组
赵小峰班组
田青兵班组
刘资利班组
郑宇超班组
牛朝发班组
张海川班组
高纪涛班组
王银华班组
罗兴忠班组
王立涛班组
徐龙班组
章荣平班组
李文兵班组
郑欧班组
丁浩宣班组
吕友武班组
马明刚班组
代永昊班组
黄铁班组
杨成班组
张毅班组
李德宝班组
王坤班组
常征班组
孙明青班组
陈泽成班组
杨廷泽班组
董可祥班组
王新班组
陈双双班组
郭翔翔班组
刘鹏班组
苟勇班组
杨中保班组
李福民班组
曹成存班组
赵威班组
黄昌成班组
杨汝兵班组
吕香港班组
雷飞班组
唐顺兴班组
龙治霖班组
黄勇班组
柳夕南班组
冯晓华班组
刘前汉班组
周世虎班组
青国勇班组
吴中海班组
朱承胜班组
唐双全班组
王龙班组
刘彦雷班组
尹乾前班组
胡庆军班组
吴庆鹏班组
杨树春班组
李年兵班组
赵雨刚班组
朱本龙班组
章荣和班组
刘和林班组
李来水班组
杨万飞班组
陈海滨班组
唐伟伟班组
姚久付班组
张宏韬班组
汪贻龙班组
秦深财班组
刘丛新班组
龚强强班组
罗鑫班组
刘焰金班组
黄承寿班组
郑文锋班组
阮祖红班组
张蒙学班组
王顺林班组
潘义磊班组
马保班组
吕计划班组
宣典雄班组
金杰班组
张文安班组
崔居万班组
王帅班组
孙致云班组
丁占飞班组
何耀龙班组
徐响班组
谢道发班组
汪剑班组
昌希龙班组
杜加明班组
刘健康班组
杨世宽班组
龚大明班组
李仲班组
夏维亚班组
杨学锋班组
杨正柱班组
郑国锋班组
谢小恶班组
黄强林班组
李宝山班组
任定高班组
李鑫班组
杨兴君班组
江桥班组
李树海班组
蔡海林班组
谢新宽班组
周恩辉班组
王云锡班组
吴义厚班组
黄治祥班组
张小红班组
杨五良班组
刘泽江班组
许吉超班组
叶冬冬班组
洪金涛班组
单海峰班组
张海涛班组
唐孝明班组
叶朝磊班组
左华彪班组
钱钦正班组
黄国兵班组
王长生班组
王健强班组
蒲道海班组
尹良国班组
董平利班组
黄飞班组
刘建军班组
申建普班组
刘贤保班组
周海洋班组
李清河班组
陈继林班组
段志君班组
侯大跃班组
段祥宇班组
王坤班组
刘士平班组
赵振强班组
方年春班组
黄勇班组
卢永权班组
杨照伟班组
何之倬班组
王足结班组
王汝鑫班组
古瑞班组
张勇班组
刘继承班组
徐雨龙班组
代兵班组
王飞班组
何计划班组
郭超班组
宋广春班组
补师林班组
代贵华班组
黄安印班组
杨长瑞班组
陶发明班组
江成平班组
曾明进班组
刘闩班组
刘昕班组
何勇班组
王仕斌班组
张仪伟班组
周勇勇班组
林祥班组
伍德明班组
刘杰班组
刘文成班组
叶辉班组
王郁班组
张云班组
李斌班组
魏在华班组
周祖水班组
王旭阳班组
周云班组
程志龙班组
朱涛班组
江双福班组
肖顺班组
张腾飞班组
王永辉班组
杨光东班组
陈龙进班组
郑伟班组
李勇军班组
张建明班组
吴限班组
江军班组
杨长和班组
朱纪倍班组
夏万年班组
赵华健班组
杨松伟班组
王务红班组
张稳栓班组
笪淦班组
李元帅班组
杨海平班组
蔡来云班组
张文武班组
谷宇班组
杨应辉班组
赵必春班组
贺中林班组
李泽明班组
万朝军班组
王浪班组
斯勋班组
杨福望班组
叶雄亮班组
江义班组
邱蒙蒙班组
任冰峰班组
蔡宁班组
张勇班组
黄少杰班组
常德地班组
刘孟德班组
高生班组
刘文虎班组
王良能班组
田宗华班组
杨青班组
董兴亮班组
金生班组
董峰豹班组
刘小山班组
陈宏坤班组
段宝强班组
蒲民班组
黄本初班组
高磊班组
张志班组
姚海强班组
吴庆欢班组
徐南班组
俞前华班组
孔维鸿班组
贺广飞班组
张林班组
张荣贵班组
钱小林班组
程琦鑫班组
赵代银班组
鲍友杰班组
孔亚康班组
刘梁玉班组
孟拉坡班组
叶晓班组
任家泉班组
尹成全班组
朱锋东班组
郑小林班组
吴德勇班组
李飞班组
程文轩班组
豆帅兵班组
王雷班组
王攀班组
吕飞班组
胡孔友班组
贾乐班组
李业亮班组
吴启贵班组
谢亚东班组
刘长军班组
张光伟班组
王勇杰班组
胡长军班组
陈军班组
陈桥班组
夏家奇班组

361
api/standard_test.py Normal file
View File

@ -0,0 +1,361 @@
from globalData import GlobalData
from utils import standardize_name, clean_useless_team_leader_name, standardize_sub_company, standardize_project_name, \
standardize_projectDepartment, standardize_team_name, check_standard_name_slot_probability
import time
from apscheduler.schedulers.blocking import BlockingScheduler
from globalData import GlobalData
# def job():
# print("[Info] Executing update_from_redis...")
# GlobalData.update_from_redis()
#
#
GlobalData.update_from_redis()
def check_standard_name_slot_probability_test():
slot_list = [{"constructionUnit": "合肥供电公司"},
{
"date": "今天",
"constructionUnit": "芜湖供电公司"
},
{
"date": "今天",
"implementationOrganization": "送电一分公司"
},
{
"date": "今天",
"subcontractor": "百瑞建设发展有限公司"
},
{
"date": "今天",
"subcontractor": "安徽宝德电力建设工程有限"
},
{
"date": "今天",
"teamName": "徐局班组"
}
]
for slot in slot_list:
match_results = check_standard_name_slot_probability(12, slot)
print(f"加权混合策略 项目部名称 输入: 原始槽位:{slot},输出: {match_results}")
def standardize_team_leader_test():
team_leader_list = [
"李东班组",
"磐基班组",
"章永班组",
"张勇班组",
"王治国班组",
"代贵华班组",
"黄安印班组",
"刘闩班组",
"王虎班组",
"周勇勇班组",
"魏在华班组",
"王礼良班组",
"林学刚班组",
"崔新荣班组",
"江军班组",
"笪淦班组",
"杨海平班组",
"蔡来云班组",
"贺中林班组",
"何勇班组",
"韦幸朝班组",
"刘文虎班组",
"金生班组",
"段宝强班组",
"何计划班组",
"刘兆班组",
"徐南班组",
"贺广飞班组",
"孙泽栋班组",
"钱小林班组",
"朱锋东班组",
]
for item in team_leader_list:
match_results = standardize_team_name(item, GlobalData.simply_to_standard_team_leader_name_map,
GlobalData.pinyin_simply_to_standard_team_leader_name_map, lower_score=70, high_score=90)
# match_results = standardize_name(item, clean_useless_team_leader_name, GlobalData.simply_to_standard_team_leader_name_map,
# GlobalData.pinyin_simply_to_standard_team_leader_name_map, lower_score=70, high_score=90)
print(f"班组长名匹配 输入: {item}-> 输出: {match_results}")
def standardize_company_test():
test_cases = [
("送一分公司"),
("送二分公司"),
("变电分公司"),
("建筑分公司"),
("检修试验分公司"),
("宏源电力公司"),
("宏源电力限公司"),
("宏源电力限公司线路"),
("宏源电力限公司变电"),
("送一分"),
("送二分"),
("变电分"),
("建筑分"),
("检修试验分"),
("宏源电力"),
("红源电力"),
("宏源电力有限"),
("宏源电力限线路"),
("宏源电力限变电"),
]
print(f"加权混合策略 分公司名匹配**********************")
start = time.perf_counter()
for item in test_cases:
match_results = standardize_sub_company(item,GlobalData.simply_to_standard_company_name_map, GlobalData.pinyin_simply_to_standard_company_name_map,70,90)
print(f"加权混合策略 分公司名匹配 输入: {item}-> 输出: {match_results}")
end = time.perf_counter()
print(f"加权混合策略 耗时: {end - start:.4f}")
def standardize_construction_test():
test_cases = [
("合肥供电公司"),
("淮北供电公司"),
("六安市城郊供电公司"),
]
print(f"加权混合策略 建管单位名匹配**********************")
start = time.perf_counter()
for item in test_cases:
match_results = standardize_sub_company(item,GlobalData.simply_to_standard_construct_name_map, GlobalData.pinyin_simply_to_standard_construct_name_map,70,90)
print(f"加权混合策略 建管单位名匹配 输入: {item}-> 输出: {match_results}")
def standardize_project_test():
test_cases = [
("金牛变电站新建建筑"),
("金牛变电站建筑工程"),
("金牛新建工程"),
("金牛新建工程调试"),
("金牛新建调试工程"),
("金牛变电站工程"),
("芦集"),
("芦集变电站"),
("安庆四变电站"),
("锦绣变电站"),
("滁州护桥变电站"),
("合州换流站"),
("陕北合州换流站"),
("陕北安徽合州换流站"),
("金牛变电站"),
("香涧鹭岛工程"),
("延庆换流站"),
("国网延庆换流站"),
("国网北京延庆换流站"),
("陶楼广银线路工程"),
("紫蓬变电站"),
("宿州萧砀变电站"),
("冯井变电站"),
("富邦秋浦变电站"),
("包河玉龙变电站"),
("绿雪莲塘工程"),
("合肥循环园工程"),
("合肥长临河工程"),
("合肥中心变"),
("锁库变电站工程"),
("槽坊工程"),
("富东2798线"),
# ("安庆四500kV变电站新建工程(PROJ-2024-0862)"),
# ("锦绣-常青π入中心变电站220kV架空线路工程(PROJ-2024-1206)"),
# ("渝北±800千伏换流站电气安装A包(调试部分)(PROJ-2024-1192)"),
# ("先锋-泉河π入安庆四变电站220kV线路工程(PROJ-2024-0834)"),
# ("安徽滁州护桥220kV变电站2号主变扩建工程(PROJ-2024-0821)"),
# ("合州士800千伏换流站电气安装A包(PROJ-2025-0056)"),
# ("卫田-陶楼T接首业变电站110kV电缆线路工程(PROJ-2024-1236)"),
# ("谯城(亳三)-希夷220kV线路工程(PROJ-2024-1205)"),
]
print(f"去不重要词汇 工程名匹配******************************************")
start = time.perf_counter()
for item in test_cases:
match_results = standardize_project_name(item, GlobalData.simply_to_standard_project_name_map,
GlobalData.pinyin_simply_to_standard_project_name_map, 70, 90)
print(f"***************工程名匹配 输入: {item}-> 输出: {match_results}")
end = time.perf_counter()
print(f"词集匹配 耗时: {end - start:.4f}")
def standardize_program_test():
print(f"项目名匹配******************************************")
oral_program_name_list = [
("金上第一项目部"),
("第一项目部金上"),
# ("第1项目部"), # 期望返回所有"第三项目管理部"
# ("第2项目部"),
# ("第3项目部"),
# ("第4项目部"),
# ("第5项目部"),
# ("第6项目部"),
# ("第7项目部"),
# ("第8项目部"),
# ("第9项目部"),
# ("第10项目部"),
# ("第11项目部"),
# ("第12项目部"),
# ("第13项目部"),
# ("电缆班"),
# ("调试1队"),
# ("调试2队"),
# ("调试3队"),
# ("调试4队"),
# ("调试5队"),
# ("第一项目管理部"),
# ("第二项目管理部"),
# ("第五项目管理部"),
# ("第十一项目管理部(萧砀线路)"),
# ("第三项目管理部(张店线路)"),
# ("第三项目管理部(岳西线路)"),
# ("第五项目管理部(蚌埠)"),
# ("第三项目管理部(六安线路)"),
# ("第十一项目管理部(宿州线路)"),
# ("调试一队"),
# ("调试二队"),
# ("调试三队"),
# ("电缆班"),
]
for company in GlobalData.standard_company_name_list:
for program in oral_program_name_list:
match_results = standardize_projectDepartment(company, program, GlobalData.standard_company_program, high_score=90)
print(f"加权混合策略 项目部名称 输入: 公司:{company},项目部:{program}-> 输出: {match_results}")
def standardize_sub_constractor_test():
test_cases = [
("怀电能源科技"),
("泰央建设有限责任公司"),
("泓源电力建设有限公司"),
("怀电能源科技公司"),
("宝德电力公司"),
("亿甲建筑公司"),
]
print(f"加权混合策略 分包单位名匹配**********************")
start = time.perf_counter()
for item in test_cases:
match_results = standardize_sub_company(item,GlobalData.simply_to_standard_constractor_name_map, GlobalData.pinyin_simply_to_standard_constractor_name_map,70,90)
print(f"分包单位名匹配 输入: {item}-> 输出: {match_results}")
def get_file_name():
import os
# 你想要遍历的目录路径
target_dir = '/Users/wangvivi/Desktop/Work/2025项目材料/送变电大模型/知识库文档/送变电文档合并V5' # ← 请替换为你的目标目录路径
# 存储文件名的列表
all_file_names = []
# 遍历目录及其子目录
for root, dirs, files in os.walk(target_dir):
for file in files:
all_file_names.append(file)
# 写入 name.txt 文件
output_path = 'name.txt' # 会生成在当前运行目录下
with open(output_path, 'w', encoding='utf-8') as f:
for name in all_file_names:
f.write(name + '\n')
print(f"共收集了 {len(all_file_names)} 个文件名,已写入 {output_path}")
class Message:
def __init__(self, role, content):
self.role = role
self.content = content
class Message:
def __init__(self, role, content):
self.role = role
self.content = content
def history_message():
from collections import namedtuple
Message = namedtuple("Message", ["role", "content"])
messages = [
# Message("user", "延庆换流站今天有多少作业计划"),
# Message("assistant", "2025-04-23 ±500KV延庆换流站备用换流变安装(PROJ-2025-0162)风险等级为2级的有0项3级的有0项4级的有1项5级的有0项一共有1项作业计划"),
# Message("user", "河州换流站今天有多少作业计划"),
# Message("assistant", "您说的工程名可能是: 第1个合州±800千伏换流站电气安装A包(PROJ-2025-0056) 第2个合州换流站-文都500千伏线路工程(PROJ-2024-1089) 第3个陕北-安徽直流工程合州±800千伏换流站土建A包(PROJ-2024-0312) 第4个文都-官山改接入合州换流站500千伏线路工程(PROJ-2024-1090) 请确认您要选择哪一个"),
Message("user", "第一个")
]
latest_message = messages[-1]
latest_user_question = latest_message.content if latest_message.role == "user" else ""
time_prefixes = ["今天", "昨天", "本周", "下周", "明天", "今日"]
history_messages = [] if any(prefix in latest_user_question for prefix in time_prefixes) else messages[:-1]
print("len(history_messages):\n", len(history_messages))
oldest_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[:2]])
last_chat_history = "\n".join([f"{msg.role}: {msg.content}" for msg in history_messages[-2:]])
print("oldest_chat_history:\n", oldest_chat_history)
print("last_chat_history:\n", last_chat_history)
print("latest_user_question:\n", latest_user_question)
def standardize_program():
from rapidfuzz import process, fuzz
# query = "金上第一项目"
# choices = [
# "第五项目管理部(阜阳)",
# "第一项目管理部(金上)",
# "第二项目管理部(香鹭西段)",
# "第十一项目管理部(宣城)",
# "第八项目管理部(芜湖)",
# "第十三项目管理部(黄山)",
# "第六项目管理部(滁州)",
# "第四项目管理部(甘浙)",
# "第九项目管理部(马鞍山)",
# "第三项目管理部(香鹭东段)",
# "第一项目管理部(天津)"
# ]
query = "第一金上"
choices = [
"第五阜阳",
"第一金上",
"第二香鹭西段",
"第十一宣城",
"第八芜湖",
"第十三黄山",
"第六滁州",
"第四甘浙",
"第九马鞍山)",
"第三香鹭东段",
"第一天津"
]
match = process.extractOne(query, choices, scorer=fuzz.WRatio)
print(match)
def get_size():
import sys
total_size = sys.getsizeof(GlobalData.standard_project_name_list) + sys.getsizeof(GlobalData.simply_to_standard_project_name_map) + sys.getsizeof(GlobalData.pinyin_simply_to_standard_project_name_map)
print(f"standard_project size: {total_size} bytes")
total_size = sys.getsizeof(GlobalData.standard_construct_name_list) + sys.getsizeof(GlobalData.simply_to_standard_construct_name_map) + sys.getsizeof(GlobalData.pinyin_simply_to_standard_construct_name_map)
print(f"standard_construct size: {total_size} bytes")
total_size = sys.getsizeof(GlobalData.standard_constractor_name_list) + sys.getsizeof(GlobalData.simply_to_standard_constractor_name_map) + sys.getsizeof(GlobalData.pinyin_simply_to_standard_constractor_name_map)
print(f"standard_constractor size: {total_size} bytes")
total_size = sys.getsizeof(GlobalData.standard_team_leader_name_list) + sys.getsizeof(GlobalData.simply_to_standard_team_leader_name_map) + sys.getsizeof(GlobalData.pinyin_simply_to_standard_constractor_name_map)
print(f"standard_team size: {total_size} bytes")
standardize_project_test()
# standardize_program()
# history_message()
# standardize_team_leader_test()
#
# standardize_sub_constractor_test()
#
# check_standard_name_slot_probability_test()
#
# standardize_construction_test()
# standardize_program_test()

View File

@ -1,3 +1,4 @@
import os
from enum import Enum
from typing import cast, Callable
@ -10,7 +11,7 @@ import re
from globalData import GlobalData
from constants import USELESS_COMPANY_WORDS, USELESS_PROJECT_WORDS, CONSTRUCTION_UNIT, IMPLEMENTATION_ORG, \
SUBCONTRACTOR, PROJECT_NAME, PROJECT_DEPARTMENT, RISK_LEVEL
SUBCONTRACTOR, PROJECT_NAME, PROJECT_DEPARTMENT, RISK_LEVEL, TEAM_NAME
# 数字转换表1-20常见数字
digit_to_chinese = {
@ -43,10 +44,78 @@ def text_to_pinyin(text):
return ''.join(lazy_pinyin(text, Style.TONE2))
def load_standard_data(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
#从文本文件路径加载json字符串
def load_standard_json_data(path):
if not os.path.exists(path):
print(f"[Error] Local file not found: {path}")
return {}
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"[Error] Failed to load local JSON file: {e}")
return {}
#将字典序列的josn 存入本地文件
def save_dict_to_file(data: dict, file_path: str):
"""
将字典数据保存为 JSON 文件
参数:
data (dict): 要写入的数据
file_path (str): 目标 JSON 文件路径
"""
try:
os.makedirs(os.path.dirname(file_path), exist_ok=True) # 确保目录存在
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
print(f"[Success] 数据已成功写入 JSON 文件:{file_path}")
except Exception as e:
print(f"[Error] 写入 JSON 文件失败:{e}")
#从指定文件中加载标准化的名称列表。
def load_standard_name_list(file_path: str):
"""
从指定文件中加载标准化的名称列表
参数:
file_path (str): 文件路径文件应包含标准化的名称列表每行一个名称
返回:
list: 从文件中读取的标准化名称列表
异常:
FileNotFoundError: 如果文件不存在抛出此异常
Exception: 如果读取文件时发生其他错误抛出此异常
"""
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} 不存在", flush=True)
raise FileNotFoundError(f"错误:文件 {file_path} 不存在")
except Exception as e:
print(f"读取文件时发生错误:{e}", flush=True)
raise Exception(f"错误:文件 {file_path} 不存在")
#将标准化名称列表写入指定文件中,每行一个名称。
def save_standard_name_list_to_file(name_list, file_path):
"""
将标准化名称列表写入指定文件中每行一个名称
参数:
name_list (list): 要写入文件的名称字符串列表
file_path (str): 要写入的目标文件路径
"""
try:
os.makedirs(os.path.dirname(file_path), exist_ok=True) # 确保文件夹存在
with open(file_path, 'w', encoding='utf-8') as file:
for name in name_list:
file.write(f"{name}\n")
print(f"[Success] 名称列表已写入文件:{file_path}")
except Exception as e:
print(f"[Error] 写入文件失败:{e}")
def extract_number(text):
"""
@ -90,7 +159,7 @@ def fuzzy_match_and_filter(input_key, match_pool, mapping_dict, lower_score=70,
"""
match_results = process.extract(input_key, match_pool, scorer=cast(Callable, WRatio), limit=len(match_pool))
high_conf_matches = [(m[0], m[1]) for m in match_results if m[1] >= lower_score]
print(f"匹配结果:{high_conf_matches}")
print(f"{input_key}匹配结果:{high_conf_matches}")
if not high_conf_matches:
return []
@ -170,6 +239,21 @@ def standardize_name_only_high_score(input_name, clean_func, simply_map, pinyin_
result = fuzzy_match_and_filter_only_high_score(pinyin_input, list(pinyin_map.keys()), pinyin_map, high_score)
return result
#标准化班组名称
def standardize_team_name(input_name, simply_map, pinyin_map, lower_score=70, high_score=90):
"""
对用户输入的班组名称进行标准化返回最匹配的标准班组名列表
:param input_name: 原始中文班组名称
:param simply_map: 清洗后的班组名称 标准班组名称映射
:param pinyin_map: 洗后班组名称的拼音 标准班组名称名映射
:param lower_score: 模糊匹配分数下限
:param high_score: 高置信匹配分数阈值
:return: 匹配的标准公司名列表
"""
return standardize_name(input_name, clean_useless_team_leader_name, simply_map, pinyin_map, lower_score, high_score)
def standardize_sub_company(input_name, simply_map, pinyin_map, lower_score=55, high_score=80):
"""
对用户输入的子公司名称进行标准化返回最匹配的标准公司名列表
@ -332,7 +416,7 @@ def generate_project_prompt(matched_projects, original_name="", type="项目部
for idx, item in enumerate(matched_projects, start=1):
html_parts.append(f"""
<div class="project-entry">
<text class="label"><strong>{idx}</strong>{item}</text><br>
<text class="label"><strong>{idx}</strong>{item}</text><br>
</div>
""")
html_parts.append("<p>请确认您要选择哪一个?</p>")
@ -353,37 +437,12 @@ def generate_confirm_prompt(matched_projects, original_name="", type="项目部
for idx, item in enumerate(matched_projects, start=1):
html_parts.append(f"""
<div class="project-entry">
<text class="label"><strong>{idx}</strong>{item}</text><br>
<text class="label"><strong>{idx}</strong>{item}</text><br>
</div>
""")
html_parts.append("<p>请确认您要选择哪一个?</p>")
return "\n".join(html_parts)
def load_standard_name(file_path: str):
"""
从指定文件中加载标准化的名称列表
参数:
file_path (str): 文件路径文件应包含标准化的名称列表每行一个名称
返回:
list: 从文件中读取的标准化名称列表
异常:
FileNotFoundError: 如果文件不存在抛出此异常
Exception: 如果读取文件时发生其他错误抛出此异常
"""
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} 不存在", flush=True)
raise FileNotFoundError(f"错误:文件 {file_path} 不存在")
except Exception as e:
print(f"读取文件时发生错误:{e}", flush=True)
raise Exception(f"错误:文件 {file_path} 不存在")
class CheckResult(Enum):
NO_MATCH = 0 # 不符合检查条件
@ -405,6 +464,8 @@ useless_company_words_pattern = re.compile("|".join(USELESS_COMPANY_WORDS))
project_symbols_pattern = re.compile(r"[A-Za-z0-9\s\W_]+")
company_symbols_pattern = re.compile(r"[\s\W_]+")
useless_team_leader_words_pattern = re.compile("班组")
def clean_useless_project_name(name: str) -> str:
# 去掉无意义词
@ -420,6 +481,10 @@ def clean_useless_company_name(name: str) -> str:
name = company_symbols_pattern.sub("", name)
return name.strip()
def clean_useless_team_leader_name(name: str) -> str:
# 去掉无意义词
name = useless_team_leader_words_pattern.sub("", name)
return name.strip()
#槽位缺失检查
def check_lost(int_res, slot):
@ -542,7 +607,16 @@ def check_standard_name_slot_probability(int_res, slot) -> tuple:
else:
prompt = generate_project_prompt(match_results, original_name=slot[PROJECT_DEPARTMENT], type="项目名")
return CheckResult.NEEDS_MORE_ROUNDS, prompt
if key == TEAM_NAME:
print(f"check_standard_name_slot 原始班组名 : {slot[TEAM_NAME]}")
match_results = standardize_team_name(value, GlobalData.simply_to_standard_team_leader_name_map,
GlobalData.pinyin_simply_to_standard_team_leader_name_map, 70, 90)
print(f"check_standard_name_slot 匹配后班组名: result:{match_results}", flush=True)
if match_results and len(match_results) == 1:
slot[key] = match_results[0]
else:
prompt = generate_project_prompt(match_results, original_name=slot[TEAM_NAME], type="班组名称")
return CheckResult.NEEDS_MORE_ROUNDS, prompt
if key == RISK_LEVEL:
if slot[RISK_LEVEL] not in ["2级", "3级", "4级", "5级"] and slot[RISK_LEVEL] not in ["二级", "三级", "四级",
"五级"]:

View File

@ -39,10 +39,20 @@ BASE_DATA = {
"安徽明生电力投资集团有限公司科创基地项目(一期)(PROJ-2024-1035)"
"九号工程",
"合州变电站",
"合州换流站"
"合州换流站",
"金牛变电站建筑",
"金牛变电站建筑部分",
"合州换流站线路",
"合州换流站安庆段",
"当涂变电站工程调试部分",
"清同5737线",
"宿州萧砀线路工程建筑部分",
"1000kV淮芜线(PROJ-2020-0204-0003)",
"35kV接地极线路雁淮线",
"110kV接地极线路吉泉线(PROJ-2020-0204-0002)"
],
# 项目部名称
"project_departments": ["调试一队", "第9项目管理部","第9项目管理部门", "金上第十一项目部门", "第八项目管理部(合肥)", "肥东9号项目部",
"project_departments": ["第一项目部金上","调试一队", "第9项目管理部","第9项目管理部门", "金上第十一项目部门", "第八项目管理部(合肥)", "肥东9号项目部",
"金上第一项目部管理部(池州黄山)", "第一项目部管理部(肥东)", "调试四队","第一项目部","第10项目管理部特高压部门"],
# 项目经理
"project_managers": ["陈少平项目经理", "范文立项目经理", "何东洋项目经理"],
@ -1052,7 +1062,7 @@ TEMPLATE_CONFIG = {
]
},
"工程进度查询": {
"date": ["今日", "昨日", "2024年5月24日", "5月24日", "今天", "昨天","2025-04-09"],
"date": ["当前", "今日", "昨日", "2024年5月24日", "5月24日", "今天", "昨天","2025-04-09"],
"templates": [
("{date}{project_name}现场进度如何?", ["date", "project_name"]),
("{date}{project_name}进度情况", ["date", "project_name"]),