From 206bc6276f8b9052ec34b216ff088749bc7dc4fa Mon Sep 17 00:00:00 2001 From: zy123 <646228430@qq.com> Date: Fri, 1 Nov 2024 17:55:26 +0800 Subject: [PATCH] =?UTF-8?q?11.1=E9=80=82=E9=85=8D=E8=B4=A7=E7=89=A9?= =?UTF-8?q?=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flask_app/general/format_date.py | 5 +- flask_app/main/截取pdf.py | 2 +- .../static/提示词/小解析基本信息货物标.txt | 11 +- flask_app/testdir/test3.py | 604 ++++-------------- flask_app/货物标/基础信息解析main.py | 4 +- flask_app/货物标/截取pdf货物标版.py | 155 +++-- .../货物标/无效标和废标和禁止投标整合main.py | 7 +- flask_app/货物标/资格审查main.py | 43 +- 8 files changed, 285 insertions(+), 546 deletions(-) diff --git a/flask_app/general/format_date.py b/flask_app/general/format_date.py index 2a731fc..8f62887 100644 --- a/flask_app/general/format_date.py +++ b/flask_app/general/format_date.py @@ -20,7 +20,8 @@ def format_chinese_date(date_str): # print("------------") # print(f"原始输入: {date_str}") - + # 预处理:删除第一个数字之前的所有字符 + date_str = re.sub(r'^[^\d]*', '', date_str) # 1. 删除所有空格 date_str = ''.join(date_str.split()) @@ -109,7 +110,7 @@ def format_chinese_date(date_str): if __name__ == "__main__": input_dates = [ # 完整的日期和时间 - "2021年 6月 18日 15点 00分", + "开标日期是2021年 6月 18日 15点 00分", "2019年7月18日09:30", "20 19 年7 月18日 09: 30整(北京时间)", "2020年02月05日12时30分45秒", diff --git a/flask_app/main/截取pdf.py b/flask_app/main/截取pdf.py index a68663b..e19e88b 100644 --- a/flask_app/main/截取pdf.py +++ b/flask_app/main/截取pdf.py @@ -157,7 +157,7 @@ def extract_pages_tobidders_notice(pdf_path, output_folder, begin_pattern, begin ) else: end_pattern = re.compile( - rf'第[一二三四五六七八九十百千]+?(?:{chapter_type})\s*[\u4e00-\u9fff]+\s*$' + rf'第[一二三四五六七八九十百千]+(?:章|部分)\s*[\u4e00-\u9fff]+\s*$' ) # print(f"使用默认的 end_pattern: {end_pattern.pattern}") # 打印默认的 end_pattern # 定义基础的 mid_pattern diff --git a/flask_app/static/提示词/小解析基本信息货物标.txt b/flask_app/static/提示词/小解析基本信息货物标.txt index fb30fce..3714e0b 100644 --- a/flask_app/static/提示词/小解析基本信息货物标.txt +++ b/flask_app/static/提示词/小解析基本信息货物标.txt @@ -4,7 +4,10 @@ 3.该招标文件的最高限价(或招标控制价或预算金额)是?请按json格式给我提供信息,键名为'招标控制价',若存在未知信息,在对应的键值中填'未知'。 -4.投标文件(或响应文件)递交截止时间是?请按json格式给我提供信息,键名是'投标文件递交截止日期',若存在未知信息,在对应的键值中填'未知'。 +4.投标文件(或响应文件)递交截止时间是?请按json格式给我提供信息,键名是'投标文件递交截止日期',键值为原文对应的内容,若存在未知信息,在对应的键值中填'未知'。示例输出格式如下: +{ + "投标文件递交截止日期":"以本项目在湖北省政府采购网招标公告为准(北京时间)。" +} 5.采购人(招标人)和采购代理机构(或招标代理机构)和项目的联系方式是?请按json格式给我提供信息,外层键名分别是'招标人联系方式','招标代理机构联系方式',"项目联系方式",嵌套键名至少包含"名称"和"联系电话",若还有其他字段则添加在后面,若存在未知信息,在对应的键值中填'未知'。示例输出如下: { @@ -25,7 +28,11 @@ 6.该招标文件的信息公示媒介在哪?请按json格式给我提供信息,键名是'信息公示媒介',若存在未知信息,在对应的键值中填'未知'。 -7.该项目的开标时间(或开启时间)和开标地点是?请按json格式给我提供信息,键名为'开标时间'和'开标地点',若存在未知信息,在对应的键值中填'未知'。 +7.该项目的开标时间(或开启时间)和开标地点(或开标方式)是?请按json格式给我提供信息,键名为'开标时间'和'开标地点',键值为原文对应的内容,若存在未知信息,在对应的键值中填'未知'。示例输出格式如下: +{ + "开标时间":"以本项目在湖北省政府采购网招标公告为准(北京时间)。", + "开标地点":"供应商通过供应商客户端进入江夏区政府采购电子交易系统开标大厅中进行远程开启" +} 8.请你根据招标文件信息,投标人需要递交的投标保证金(或磋商保证金)是多少?请按json格式给我提供信息,键名为'投标保证金额',键值为原文中的具体金额的完整表述,如果不需要递交保证金或者金额未知,键值为"其他"。 diff --git a/flask_app/testdir/test3.py b/flask_app/testdir/test3.py index e82dfbe..9861a98 100644 --- a/flask_app/testdir/test3.py +++ b/flask_app/testdir/test3.py @@ -1,480 +1,144 @@ -def post_process_baseinfo(base_info): +# -*- encoding:utf-8 -*- +import json +import re + + +def is_numeric_key(key): + # 这个正则表达式匹配由数字、点、括号中的数字或单个字母(小写或大写)组成的字符串, + # 字母后跟数字,或数字后跟字母,单个字母后跟点,但不能是字母-数字-字母的组合 + pattern = r'^[\d.]+$|^\(\d+\)$|^(\d+)$|^[a-zA-Z]$|^[a-zA-Z]\d+$|^\d+[a-zA-Z]$|^[a-zA-Z]\.$' + return re.match(pattern, key) is not None + + +def contains_number_or_index(key, value): + # 判断值是否是数字或数字字符串 + is_number = isinstance(value, (int, float)) or (isinstance(value, str) and value.isdigit()) + # 判断键是否包含 "序号" + contains_index = '序号' in key + # 判断值中是否包含数字 + contains_digit = isinstance(value, str) and re.search(r'\d+', value) + # 判断值中是否包含中文字符 + contains_chinese = isinstance(value, str) and re.search(r'[\u4e00-\u9fff]', value) + # 如果值中包含数字但也有中文字符,则保留(返回 False) + if contains_digit and contains_chinese: + return False + # 如果值是数字或包含数字,且不包含中文字符,或者键包含 "序号",返回 True + return is_number or contains_index or contains_digit +def preprocess_dict(data): + if isinstance(data, dict): + if len(data) > 1: + # 检查是否所有值都是 "" 或 "/" + if all(v == "" or v == "/" or (isinstance(v, list) and not v) for v in data.values()): + return list(data.keys()) + else: + processed = {} + for k, v in data.items(): + if not contains_number_or_index(k, v): + processed_v = preprocess_dict(v) + if processed_v != "": # 只添加非空值 + processed[k] = processed_v + return processed + else: + return {k: preprocess_dict(v) for k, v in data.items()} + elif isinstance(data, list): + return [preprocess_dict(item) for item in data] + else: + return data + +def process_dict(data): """ - 在 'base_info' 任务完成后执行的函数。 - 确保在缺少某些键时,返回 good_list=[]。 + 递归处理字典,将符合条件的键值对进行转换。 - 参数: - - base_info (dict): 原始的 base_info 数据。 + 如果键是数字或特定格式的字符串,则将其值放入 'items' 列表中并排序。 + 对于非数字键,如果对应的值是列表且列表中只有一个元素,则将其展平为单个元素。 - 返回: - - tuple: (处理后的 base_info, good_list) + Args: + data (dict): 输入的字典数据。 + + Returns: + dict 或 list 或 原始数据类型: 处理后的数据结构。 """ - try: - pure_base_info = base_info.get("基础信息", {}) - # 尝试提取 '货物列表',若中间某个键不存在,返回 good_list=[] - procurement_reqs = pure_base_info.get('采购要求', {}) - technical_requirements = procurement_reqs.get('技术要求', {}) - good_list = technical_requirements.pop('货物列表', []) # 如果 '货物列表' 不存在,返回 [] + if not isinstance(data, dict): + return data - # 删除 '货物列表' 后更新原始的 base_info - if '技术要求' in procurement_reqs and not technical_requirements: - # 若技术要求为空,删除该键 - procurement_reqs.pop('技术要求') + result = {} + numeric_keys = [] + non_numeric_keys = {} - if '采购要求' in pure_base_info and not procurement_reqs: - # 若采购要求为空,删除该键 - pure_base_info.pop('采购要求') + # 分类键为数字键和非数字键 + for key, value in data.items(): + if is_numeric_key(key): + numeric_keys.append((key, value)) + else: + non_numeric_keys[key] = value - # 更新基础信息 - base_info['基础信息'] = pure_base_info + # 处理数字键,将其值递归处理后放入 'items' 列表中 + if numeric_keys: + def sort_key(item): + key = item[0] + if re.match(r'^\d+$', key): # 纯整数 + return (int(key),) + elif re.match(r'^\d+\.\d+$', key): # 单层小数点 + return (float(key),) + else: # 多层序号,按字符串处理 + return tuple(map(int, key.split('.'))) + # 按键排序,确保顺序一致 + numeric_keys_sorted = sorted(numeric_keys, key=sort_key) + result['items'] = [process_dict(item[1]) for item in numeric_keys_sorted] - return base_info, good_list - except Exception as e: - return base_info, [] # 返回空列表 + # 处理非数字键 + for key, value in non_numeric_keys.items(): + if isinstance(value, list): + processed_list = [] + for item in value: + if isinstance(item, dict): + # 处理字典中只有一个键值对的情况 + if len(item) == 1: + processed_item = process_dict(list(item.values())[0]) + else: + processed_item = process_dict(item) + else: + processed_item = process_dict(item) + + # 如果处理后的项是只包含一个元素的列表,则展平它 + if isinstance(processed_item, list) and len(processed_item) == 1: + processed_item = processed_item[0] + + processed_list.append(processed_item) + + # 新增逻辑:如果 processed_list 只有一个元素,则将其展平为单个元素 + if len(processed_list) == 1: + result[key] = processed_list[0] + else: + result[key] = processed_list + else: + # 如果值不是列表,直接递归处理 + result[key] = process_dict(value) + + # 如果结果只有一个键 'items',则直接返回 'items' 列表 + if len(result) == 1 and 'items' in result: + return result['items'] + + # 检查如果所有键对应的值都是空列表,则将键名转换成列表项 + if all(isinstance(v, list) and not v for v in result.values()): + return list(result.keys()) + + return result data={ - "基础信息": { - "招标人/代理信息": { - "招标人": "广水市公路管理局", - "招标人联系方式": { - "名称": "广水市公路管理局", - "联系电话": "17362698785", - "地址": "随州市广水市四贤路 7号应山办事处南门" - }, - "招标代理机构": "湖北众恒永业工程项目管理有限公司广水分公司", - "招标代理机构联系方式": { - "名称": "湖北众恒永业工程项目管理有限公司广水分公司", - "联系电话": "13997896775", - "地址": "广水市名都花园 22栋" - }, - "项目联系方式": { - "名称": "闵杨、喻亚", - "联系电话": "13997896775、15337331616" - } - }, - "项目信息": { - "项目名称": "107国道交通信号灯及安全防护设施采购项目", - "项目编号": "HBZHYY-2021-001", - "项目概况": "107国道交通信号灯及安全防护设施采购项目", - "项目基本情况": { - "1": "政府采购计划编号:2020-09-000560", - "2": "项目编号:HBZHYY-2021-001", - "3": "项目名称:107国道交通信号灯及安全防护设施采购项目", - "4": "采购方式:公开招标", - "5": "预算金额:RMB10071358.07元", - "6": "最高限价:RMB10070194.68元(一包:RMB6230708.59元、二包:RMB2175838.09元、三包:RMB1663648元)", - "7": { - "7.1": "项目概况及内容:一包:107国道交通信号灯及安全防护设施的监控抓拍系统、电子警察、信号灯、专用配套设备等。二包:107国道广水段标示标牌及标线等。三包:107国道霞家河超限检测站抓拍、超重系统等。(以上具体要求见招标文件第三章项目技术、服务及商务要求。)", - "7.2": "项目地点:107国道路段。", - "7.3": "投标人只能对此项目三个包中的一个包进行报名,若同时对两个包或两个包以上进行报名,则所有报名无效。" - }, - "8": "合同履行期限:合同签订后 6个月内。", - "9": "本项目不接受联合体投标。", - "10": "是否可采购进口产品:否。" - }, - "招标控制价": "RMB10070194.68元", - "投标竞争下浮率": "未知", - "分包": "不允许", - "是否接受联合体投标": "否" - }, - "采购要求": { - "技术要求": { - "交通信号灯": { - "单灯技术要求": "1、道路交通信号灯单灯必须符合国家标准GB14887-2011《道路交通信号灯》全部技术规定,并通过公安部交通安全产品质量监督检测中心的检测。", - "光源要求": "2、道路交通信号灯光源必须采用户外型超亮度发光二极管(LED),使用寿命不少于50000小时。", - "材质要求": "3、信号灯灯具材质为铝质金属材料。机动车信号灯灯芯透镜尺寸采用¢400mm规格,人行信号灯灯芯透镜尺寸采用¢300mm,相同规格的灯芯可以互换。信号灯外观应与目前广水市使用的信号灯外观相一致。", - "供电电路要求": "4、信号灯需采用恒流供电电路,单体信号灯功率¢400mm规格不超过20VA;¢300mm规格不超过 15VA。", - "倒计时器要求": "1、道路交通信号倒计时器安装在信号灯的上方或右方,2位数码显示倒九秒提示。当机动车信号灯采用悬臂式杆件时,机动车信号灯倒计时器规格为 800×600,当采用立柱式杆件时,倒计时器规格为 400×400。人行信号灯倒计时显示器透光面为Φ300mm或 300mm ×300mm。倒计时显示器的光学性能、工作条件、机械强度、电气性能均符合国家安全行业标准GA/T508-2004《道路交通信号倒计时显示器》的全部技术规定。", - "倒计时器运行要求": "2、倒计时器运行中遇到电磁、静电、电网等干扰时不能有死机现象。", - "倒计时器测试要求": "3、倒计时器必须经过过电压、过电流测试,具有防雷击功能。", - "倒计时器触发方式": "4、倒计时器应为学习型,并支持脉冲触发、黄灯触发及通讯式触发。", - "信号灯杆技术要求": "1、信号灯杆所属的立柱、法兰盘、地脚螺栓、螺母、垫片、加强筋等金属构件及悬臂、支撑臂、拉杆、抱箍座、夹板等附件的防腐性能应符合GB/T18226《公路交通工程钢构件防腐技术条件》的规定。", - "信号灯杆材质要求": "2、信号灯杆应采用圆形或多棱形经热镀锌处理的钢管制造;悬臂式灯杆悬臂杆与支撑杆使用圆形或多棱形的变截面型材制作,悬臂与灯杆连接端宜焊接固定法兰盘,悬臂下应留有进出线孔。", - "信号灯杆表面处理": "3、信号灯杆制作后须经过防锈处理,底层喷涂富锌防锈底漆,外层喷涂银灰色瓷漆。", - "信号灯杆底部要求": "4、信号灯灯杆距路面约 300-350mm处留有拉线孔和拉线孔门。孔门盖应设有防盗措施,孔内设置接地端子座,并与接地线可靠接驳。", - "信号灯杆顶部要求": "5、立柱式灯杆顶部安装灯具处应留有出线孔,并配备橡胶护套、电缆线回水弯挂钩,灯杆顶部应安装塑料或经防腐处理的内套式金属防水管帽。", - "悬臂式灯杆拉杆要求": "6、悬臂式灯杆拉杆宜使用圆钢制作,一端配有可调距离的螺旋扣,直径和长度根据悬臂长度确定。", - "信号灯杆法兰盘要求": "7、信号灯杆杆体底部应焊接固定法兰盘,法兰盘与杆体之间应均匀焊接加强筋。", - "人行信号灯设计要求": "8、一体式人行信号灯采用整灯嵌入式设计、结构紧凑、方便拆装、便于维护。杆体前后金属面板喷塑处理,两侧铝型材包边。" - }, - "交通监控视频子系统": { - "高清视频抓拍像机": { - "有效像素": "≥900W像素", - "最低照度": "彩色≤0.001lx", - "传感器类型": "≥1英寸全局曝光COMS/GMOS/GS COMS", - "电子快门": "至少满足 1/25s至 1/100,000s,可调", - "视频压缩标准": "至少支持H264、H265等", - "视频分辨率": "≥4096×2160,向下可设置", - "视频流帧率": "≥25fps,至少双视频流", - "图片压缩方式": "JPEG", - "图像分辨率": "≥4096(H)×2160(V)", - "强光抑制": "具备", - "API接口开放": "具备;支持标准ONVIF协议与第三方厂家设备进行互联;支持GB/T28181;应提供 SDK", - "通讯接口": "≥1个 RJ45,10M/100M/1000M自适应以太网电口;≥1个 RS-485接口", - "前端存储卡": "嵌入式,支持断网时本地存储,裸容量≥128GB", - "具备其他功能": "应具备I/O触发、RS-485触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光", - "具备其他功能2": "具备AI深度学习算法和GPU芯片", - "光圈、聚焦": "手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于 900万像素,边缘解像力不低于中心 60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能", - "防护罩类型": "室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。", - "防护等级": "≥IP66" - }, - "补光灯": { - "配置方式": "每个车道配置≥1台;补光装置必须与高清摄像设备高度匹配", - "LED管芯": "采用超高亮大功率白光LED管芯,灯珠数量不少于 20颗", - "功耗": "30W/车道≤单台平均功耗≤50W/车道,可调", - "峰值光照度(基准轴)": "≤300lx", - "峰值光照度(补光区)": "应大于等于基准轴上有效光照度的 50%", - "平均光照度": "≤50lx", - "闪光频率": "≥50Hz;补光装置应能与集成式高清摄像设备同步", - "有效补光距离": "≥25m", - "最大点亮时间": "≤4ms(可调节)", - "控制方式": "电平,同步触发方式", - "安全性": "在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染", - "使用寿命": "≥50000小时", - "防护等级": "不低于IP65", - "其它": "应配置光栅装置或遮光阻断装置" - }, - "光纤收发器": { - "1路千兆以太网": "1路千兆以太网。", - "单模单纤": "单模单纤,光接口为FC接口,满足实际传输距离要求。", - "10/100/1000M自适应以太网接口": "10/100/1000M自适应以太网接口。", - "工作环境适应性强": "工作环境适应性强,满足全天候使用的要求。", - "耐压": "耐压≥300V。" - }, - "交换机": { - "交换容量": "≥6Gbps,包转发率≥7Mpps;MAC地址列表≥8K;应具备线性转发能力;", - "以太网接口": "应至少具有 8个 10/100/1000M自适应以太网接口和至少 2个 1000M光口;", - "以太网光端口传输距离": "应不小于 40km,以太网光模块为单芯双向光模块,光口接口类型为LC型接口,光模块连接单模光纤;", - "支持协议": "至少支持 IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x等协议;", - "VLAN功能": "应具有 IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持 4个 VLAN划分;", - "路由协议": "应至少支持三层动态路由协议;", - "QOS功能": "应具有 IEEE802.1p_QOS功能;", - "组播功能": "应具有 IGMP静态组播、端口聚合、端口镜像等功能;", - "防护等级": "IP40以上等级防护;", - "设计要求": "应采用无风扇设计;", - "网管功能": "应具有网管功能。" - }, - "终端服务器": { - "结构形式": "采用嵌入式架构;", - "操作系统": "嵌入式操作系统;", - "接入路数": "提供≥12路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等;", - "主机存储": "内置 SATA接口;配置存储容量≥16T硬盘 ;", - "网络接口": "提供≥8个 RJ45 1000M网络接口;", - "其他接口": "提供 RS232、RS485、外置 USB接口、VGA接口等;", - "访问操作": "支持 Web操作访问;", - "接口协议": "至少支持 ONVIF,GB/T28181等;", - "API接口开放支持": "支持标准ONVIF协议与第三方厂家设备进行互通;支持 GB/T 28181。", - "支持套牌车检测": "可将抓拍图片与本地历史数据进行车辆特征比对分析,检测出套牌车辆,同时给出告警提示" - } - }, - "交通诱导子系统": { - "交通诱导屏": { - "主要特性": "1)温度范围-40~70℃ 2)光带宽度>130mm 3)通迅接口:RS485、网络通讯、3G网络 4)视角:水平:110°~120°垂直:55° 5)发光亮度:6500-7000 cd/m2 6)平整度≤0.5mm 7)使用寿命≥10万小时 8)平均故障时间≥1万小时 9)电源采用 n+1高可靠容错的开关电源系统 10)显示尺寸:长 3.84米×高 2.56米=9.83平方米 11)机箱要求:冷轧钢板,机箱为内外两层,内箱体为全封闭、全天候、防风雨型,符合IP65防护等级 12)抗风等级:40m/s", - "技术参数": "1)物理点间距:10mm2)物理密度:10000点/m23)发光点颜色:1R1G 4)基色:纯红+纯绿 5)模组尺寸:320mm*160mm 6)刷新频率:≥800HZ 7)工作电压:AC220V±10%,50Hz(三相五线制)8)平均功耗:350W/m2 9)最大功耗:≤700W/ m2" - } - }, - "电子警察子系统": { - "高清视频抓拍像机": { - "摄像机.有效像素": "≥900W像素", - "摄像机.最低照度": "彩色≤0.001lx", - "摄像机.传感器类型": "≥1英寸全局曝光COMS/GMOS/GS COMS", - "摄像机.电子快门": "至少满足 1/25s至 1/100,000s,可调", - "视频图像.视频压缩标准": "至少支持H264、H265等", - "视频图像.视频分辨率": "≥4096×2160,向下可设置", - "视频图像.视频流帧率": "≥25fps,至少双视频流", - "视频图像.图片压缩方式": "JPEG", - "视频图像.图像分辨率": "≥4096(H)×2160(V)", - "视频图像.强光抑制": "具备", - "协议.API接口开放": "具备;支持标准ONVIF协议与第三方厂家设备进行互联;支持GB/T28181;应提供 SDK", - "接口.通讯接口": "≥1个 RJ45,10M/100M/1000M自适应以太网电口;≥1 个 RS-485接口", - "接口.前端存储卡": "嵌入式,支持断网时本地存储,裸容量≥128GB", - "功能.具备其他功能": "应具备I/O触发、RS-485触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光", - "功能.具备其他功能.具备AI深度学习算法和GPU芯片": "具备AI深度学习算法和GPU芯片", - "高清工业级镜头.光圈、聚焦": "手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于 900万像素,边缘解像力不低于中心 60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能", - "防护罩.防护罩类型": "室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。", - "防护罩.防护等级": "≥IP66" - }, - "补光灯": { - "配置方式": "每个车道配置≥1台;补光装置必须与高清摄像设备高度匹配", - "LED管芯": "采用超高亮大功率白光LED管芯,灯珠数量不少于 20颗", - "功耗": "30W/车道≤单台平均功耗≤50W/车道,可调", - "峰值光照度(基准轴)": "≤300lx", - "峰值光照度(补光区)": "应大于等于基准轴上有效光照度的 50%", - "平均光照度": "≤50lx", - "闪光频率": "≥50Hz;补光装置应能与集成式高清摄像设备同步", - "有效补光距离": "≥25m", - "最大点亮时间": "≤4ms(可调节)", - "控制方式": "电平,同步触发方式", - "安全性": "在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染", - "使用寿命": "≥50000小时", - "防护等级": "不低于IP65", - "其它": "应配置光栅装置或遮光阻断装置" - }, - "光纤收发器": { - "1路千兆以太网": "1路千兆以太网。", - "单模单纤": "单模单纤,光接口为FC接口,满足实际传输距离要求。", - "10/100/1000M自适应以太网接口": "10/100/1000M自适应以太网接口。", - "工作环境适应性强": "工作环境适应性强,满足全天候使用的要求。", - "耐压": "耐压≥300V。" - }, - "交换机": { - "交换容量": "≥6Gbps,包转发率≥7Mpps;MAC地址列表≥8K;应具备线性转发能力;", - "以太网接口": "应至少具有 8个 10/100/1000M自适应以太网接口和至少 2个 1000M光口;", - "以太网光端口传输距离": "应不小于 40km,以太网光模块为单芯双向光模块,光口接口类型为LC型接口,光模块连接单模光纤;", - "支持协议": "至少支持 IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x等协议;", - "VLAN功能": "应具有 IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持 4个 VLAN划分;", - "动态路由协议": "应至少支持三层动态路由协议;", - "QOS功能": "应具有 IEEE802.1p_QOS功能;", - "组播功能": "应具有 IGMP静态组播、端口聚合、端口镜像等功能;", - "防护等级": "IP40以上等级防护;", - "设计要求": "应采用无风扇设计;", - "网管功能": "应具有网管功能。" - }, - "终端服务器": { - "结构形式": "采用嵌入式架构;", - "操作系统": "嵌入式操作系统;", - "接入路数": "提供≥12路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等;", - "主机存储": "内置 SATA接口;配置存储容量≥16T硬盘 ;", - "网络接口": "提供≥8个 RJ45 1000M网络接口;", - "其他接口": "提供 RS232、RS485、外置 USB接口、VGA接口等;", - "访问操作": "支持 Web操作访问;", - "接口协议": "至少支持 ONVIF,GB/T28181等;", - "API接口开放支持": "支持标准ONVIF协议与第三方厂家设备进行互通;支持 GB/T 28181。", - "支持套牌车检测": "可将抓拍图片与本地历史数据进行车辆特征比对分析,检测出套牌车辆,同时给出告警提示" - } - }, - "交通卡口子系统": { - "高清视频抓拍像机": { - "摄像机.有效像素": "≥900W像素", - "摄像机.最低照度": "彩色≤0.001lx", - "摄像机.传感器类型": "≥1英寸全局曝光COMS/GMOS/GS COMS", - "摄像机.电子快门": "至少满足 1/25s至 1/100,000s,可调", - "视频图像.视频压缩标准": "至少支持H264、H265等", - "视频图像.视频分辨率": "≥4096×2160,向下可设置", - "视频图像.视频流帧率": "≥25fps,至少双视频流", - "视频图像.图片压缩方式": "JPEG", - "视频图像.图像分辨率": "≥4096(H)×2160(V)", - "视频图像.强光抑制": "具备", - "协议.API接口开放": "具备;支持标准ONVIF协议与第三方厂家设备进行互联;支持GB/T28181;应提供 SDK", - "接口.通讯接口": "≥1个 RJ45,10M/100M/1000M自适应以太网电口;≥1 个 RS-485接口", - "接口.前端存储卡": "嵌入式,支持断网时本地存储,裸容量≥128GB", - "功能.具备其他功能": "应具备I/O触发、RS-485触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光", - "功能.具备其他功能.1": "具备AI深度学习算法和GPU芯片", - "高清工业级镜头.光圈、聚焦": "手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于 900万像素,边缘解像力不低于中心 60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能", - "防护罩.防护罩类型": "室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。", - "防护罩.防护等级": "≥IP66" - }, - "补光灯": { - "配置方式": "每个车道配置≥1台;补光装置必须与高清摄像设备高度匹配", - "LED管芯": "采用超高亮大功率白光LED管芯,灯珠数量不少于 20颗", - "功耗": "30W/车道≤单台平均功耗≤50W/车道,可调", - "峰值光照度(基准轴)": "≤300lx", - "峰值光照度(补光区)": "应大于等于基准轴上有效光照度的 50%", - "平均光照度": "≤50lx", - "闪光频率": "≥50Hz;补光装置应能与集成式高清摄像设备同步", - "有效补光距离": "≥25m", - "最大点亮时间": "≤4ms(可调节)", - "控制方式": "电平,同步触发方式", - "安全性": "在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染", - "使用寿命": "≥50000小时", - "防护等级": "不低于IP65", - "其它": "应配置光栅装置或遮光阻断装置" - }, - "光纤收发器": { - "1路千兆以太网": "1路千兆以太网。", - "单模单纤": "单模单纤,光接口为FC接口,满足实际传输距离要求。", - "10/100/1000M自适应以太网接口": "10/100/1000M自适应以太网接口。", - "工作环境适应性强": "工作环境适应性强,满足全天候使用的要求。", - "耐压": "耐压≥300V。" - }, - "交换机": { - "交换容量": "≥6Gbps,包转发率≥7Mpps;MAC地址列表≥8K;应具备线性转发能力;", - "以太网接口": "应至少具有 8个 10/100/1000M自适应以太网接口和至少 2个 1000M光口;", - "以太网光端口传输距离": "应不小于 40km,以太网光模块为单芯双向光模块,光口接口类型为LC型接口,光模块连接单模光纤;", - "支持协议": "至少支持 IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x等协议;", - "VLAN功能": "应具有 IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持 4个 VLAN划分;", - "路由协议": "应至少支持三层动态路由协议;", - "QOS功能": "应具有 IEEE802.1p_QOS功能;", - "组播功能": "应具有 IGMP静态组播、端口聚合、端口镜像等功能;", - "防护等级": "IP40以上等级防护;", - "设计要求": "应采用无风扇设计;", - "网管功能": "应具有网管功能。" - }, - "终端服务器": { - "结构形式": "采用嵌入式架构;", - "操作系统": "嵌入式操作系统;", - "接入路数": "提供≥12路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等;", - "主机存储": "内置 SATA接口;配置存储容量≥16T硬盘 ;", - "网络接口": "提供≥8个 RJ45 1000M网络接口;", - "其他接口": "提供 RS232、RS485、外置 USB接口、VGA接口等;", - "访问操作": "支持 Web操作访问;", - "接口协议": "至少支持 ONVIF,GB/T28181等;", - "API接口开放支持": "支持标准ONVIF协议与第三方厂家设备进行互通;支持 GB/T 28181。", - "支持套牌车检测": "可将抓拍图片与本地历史数据进行车辆特征比对分析,检测出套牌车辆,同时给出告警提示" - } - }, - "区间测速子系统": { - "高清视频抓拍像机": { - "1.摄像机.有效像素": "≥900W像素", - "1.摄像机.最低照度": "彩色≤0.001lx", - "1.摄像机.传感器类型": "≥1英寸全局曝光COMS/GMOS/GS COMS", - "1.摄像机.电子快门": "至少满足 1/25s至 1/100,000s,可调", - "2.视频图像.视频压缩标准": "至少支持H264、H265等", - "2.视频图像.视频分辨率": "≥4096×2160,向下可设置", - "2.视频图像.视频流帧率": "≥25fps,至少双视频流", - "3.视频图像.图片压缩方式": "JPEG", - "3.视频图像.图像分辨率": "≥4096(H)×2160(V)", - "3.视频图像.强光抑制": "具备", - "4.协议.API接口开放": "具备;支持标准ONVIF协议与第三方厂家设备进行互联;支持GB/T28181;应提供 SDK", - "5.接口.通讯接口": "≥1个 RJ45,10M/100M/1000M自适应以太网电口;≥1 个 RS-485接口", - "5.接口.前端存储卡": "嵌入式,支持断网时本地存储,裸容量≥128GB", - "5.功能.具备其他功能": "具备AI深度学习算法和GPU芯片", - "6.高清工业级镜头.光圈、聚焦": "手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于 900万像素,边缘解像力不低于中心 60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能", - "7.防护罩.防护罩类型": "室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。", - "7.防护罩.防护等级": "≥IP66" - }, - "补光灯": { - "配置方式": "每个车道配置≥1台;补光装置必须与高清摄像设备高度匹配", - "LED管芯": "采用超高亮大功率白光LED管芯,灯珠数量不少于 20颗", - "功耗": "30W/车道≤单台平均功耗≤50W/车道,可调", - "峰值光照度(基准轴)": "≤300lx", - "峰值光照度(补光区)": "应大于等于基准轴上有效光照度的 50%", - "平均光照度": "≤50lx", - "闪光频率": "≥50Hz;补光装置应能与集成式高清摄像设备同步", - "有效补光距离": "≥25m", - "最大点亮时间": "≤4ms(可调节)", - "控制方式": "电平,同步触发方式", - "安全性": "在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染", - "使用寿命": "≥50000小时", - "防护等级": "不低于IP65", - "其它": "应配置光栅装置或遮光阻断装置" - }, - "光纤收发器": { - "1路千兆以太网": "1路千兆以太网。", - "单模单纤": "单模单纤,光接口为FC接口,满足实际传输距离要求。", - "10/100/1000M自适应以太网接口": "10/100/1000M自适应以太网接口。", - "工作环境适应性强": "工作环境适应性强,满足全天候使用的要求。", - "耐压": "耐压≥300V。" - }, - "交换机": { - "交换容量": "≥6Gbps", - "包转发率": "≥7Mpps", - "MAC地址列表": "≥8K", - "线性转发能力": "应具备线性转发能力", - "以太网接口": "应至少具有 8个 10/100/1000M自适应以太网接口和至少 2个 1000M光口", - "以太网光端口传输距离": "应不小于 40km,以太网光模块为单芯双向光模块,光口接口类型为LC型接口,光模块连接单模光纤", - "支持协议": "至少支持 IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x等协议", - "VLAN": "应具有 IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持 4个 VLAN划分", - "三层动态路由协议": "应至少支持三层动态路由协议", - "QOS功能": "应具有 IEEE802.1p_QOS功能", - "IGMP静态组播": "应具有 IGMP静态组播、端口聚合、端口镜像等功能", - "防护等级": "IP40以上等级防护", - "无风扇设计": "应采用无风扇设计", - "网管功能": "应具有网管功能" - }, - "终端服务器": { - "结构形式": "采用嵌入式架构;", - "操作系统": "嵌入式操作系统;", - "接入路数": "提供≥8路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等;", - "主机存储": "内置 SATA接口;配置存储容量≥16T硬盘 ;", - "网络接口": "提供≥8个 RJ45 1000M网络接口;", - "其他接口": "提供 RS232、RS485、外置 USB接口、VGA接口等;", - "访问操作": "支持 Web操作访问;", - "接口协议": "至少支持 ONVIF,GB/T28181等;", - "API接口开放支持": "支持标准ONVIF协议与第三方厂家设备进行互通;支持 GB/T 28181。" - } - }, - "后台接入服务器": { - "1、机架式服务器": "1、机架式服务器;", - "2、处理器": "2、处理器:至少配置 2颗单颗 10核 CPU,单核 CPU主频≥2.0GHz;", - "3、内存": "3、内存:配置 128GB DDR4内存;", - "4、硬盘": "4、硬盘:配置 6块 1.2T SAS硬盘,转速≥10Krpm;", - "5、RAID": "5、RAID:配置 RAID控制器,支持 RAID0、1、10、1E、5、50、60等;", - "6、网络": "6、网络:配置双千兆网卡;", - "7、电源": "7、电源:双电源;" - }, - "存储服务器": { - "1": "4U 48盘位磁盘阵列;", - "2": "单设备配置 64位多核处理器;", - "3": "16GB缓存;", - "4": "冗余电源;", - "5": "支持 SATA硬盘;", - "6": "2个千兆网口;", - "7": "1个系统 SSD盘;", - "8": "支持视音频、图片、直接写入,支持视频高速预览、回放、下载,支持云内容灾备份,支持一体化运维,支持GB/T28181-2011、Onvif、RTSP、H265、SVAC等标准视频协议。" - }, - "硬盘": { - "容量": "4T", - "尺寸": "3.5寸", - "接口": "SATA" - }, - "室外挂箱": { - "安装方式": "采用悬挂式安装方式,悬挂于杆件立柱,高度应确保机箱下边缘距离地面净高 2.5 米以上。设备机箱安装后不得侵入机动车道建筑界限以内,不得影响车辆正常通行。设备机箱应安装牢固;", - "表面处理": "设备机箱表面应经过考漆处理,应具备防锈蚀、防盐雾、防霉菌能力;", - "内部空间": "机箱内部空间应足够大,能确保设备、装置的合理摆放,设有存放用户手册、说明书、接线图、维修记录等资料的存储盒,并有适当空间预留。机箱空间应有利于机箱内各设备单元的散热、安装、使用和维修,同时应提供设备辅助散热措施,提高系统环境适应能力;", - "防护等级": "设备机箱的结构应能防雨并能降低灰尘及有害物质的侵入,机箱门盖应有溢水槽,机箱门内侧应配备密封条,机箱顶部应具有防积水措施。机箱防护等级应达到IP55以上;", - "机械强度": "机箱结构应具有足够的机械强度,应能承受正常条件下可预料到的运输、安装、搬运、维护等过程中的操作;", - "门的设计": "机箱门的最大开启角度应大于 120°。机箱门锁应采用保险柜天地锁式的结构设计防止被非法打开,门锁至少可对上、下及左右侧中的一侧进行缩栓式保护,应具备较强的设备防砸、防盗能力。机箱应具有防盗报警功能,机箱在非正常状态下开启时能够报警提示。机箱门接缝处有耐久且有弹性的密封垫,密封垫连续设置,无间断接口。机柜门锁上后,无松动、变形现象;", - "电源保护": "机箱内设应置有具备稳压、过载、漏电、短路保护功能的电源开关和防雷保护功能的电源浪涌保护器。在熔断器和电源开关等处应有警告标志。机箱内合适位置配备接地铜排,接地铜排的截面应不小于 100 mm2,接地端子应进行防腐处理。并应设置接地标志;接地铜排应保证良好接地,接地线截面积应不小于 16mm2;", - "电源插座": "机箱内应配备不少于 2路单相 2孔扁圆电源插座、2路单相 3孔扁圆电源插座;", - "电源开关": "应具有稳压、短路、过载、漏电保护;电源保护响应时间应为纳秒级;开关的额定电压、额定电流值应满足设备正常运行的要求;机械寿命应不少于 20000次;具有良好的散热性能。", - "额外要求": "室外大机箱需满足上述使用外,还应可安装前端管理主机。" - }, - "交通管道": { - "过街管道": "主要垂直于道路中线埋设,可开挖路段采用 DN90镀锌钢管,不宜开挖路段根据现场情况采用拖拉管(DN90 PE管)。路口必须在各方向埋设双管。", - "非过街管道": "采用 PE双壁波纹管。", - "干线(纵向)路段": "两接线井之间最大距 50m。", - "管道埋设深度": "机动车道和非机动车道下管道埋设深度(管顶至路面)应≥0.7m,人行道及绿化带下管道埋设深度(管顶至路面)应≥0.5m。如不能达到上述埋设深度要求应采取混凝土包封或采用钢管等保护措施。", - "管道敷设的坡度": "应为 0.3%-0.4%,不得小于 0.25%。", - "其他敷设要求": "应参照《市政公用工程细部构造做法(湖北省)》中《交通管道预埋断面图》做法。", - "交通管道开挖后": "应按原有道路或绿化进行恢复,管线尽量敷设于人行道上,不影响后续的绿化园林施工。" - } - }, - "商务要求": "", - "服务要求": "", - "其他要求": "" - }, - "关键时间/内容": { - "投标文件递交截止日期": "2021年月日点分(北京时间)", - "投标文件递交地点": "广水市公共资源交易中心五楼号开标室", - "开标时间": "未知", - "开标地点": "广水市公共资源交易中心五楼号开标室", - "澄清招标文件的截止时间": "未知", - "投标有效期": "提交投标文件截止之日起 60日历日", - "信息公示媒介": [ - { - "名称": "中国湖北政府采购网", - "网址": "http://www.ccgp-hubei.gov.cn/" - }, - { - "名称": "中国广水网", - "网址": "http://www.zggsw.gov.cn/" - } - ] - }, - "保证金相关": { - "是否提交履约保证金": "未知", - "质量保证金": "未知" - }, - "其他信息": { - "投标费用承担": "投标人应承担所有与准备和参加投标有关的费用。不论投标的结果如何,分散采购机构和采购人均无义务和责任承担这些费用。", - "招标代理服务费": { - "收费标准": "服务费按国家规定收费标准按国家发展改革委关于印发《招标代理服务收费管理暂行办法》的通知(计价格[2002]1980 号)执行。", - "支付方": "中标方", - "支付时间": "政府采购代理缴纳中标服务费" - }, - "是否退还投标文件": "否", - "投标预备会": "不召开", - "偏离": { - "商务要求响应、偏离说明表": "第七章投标文件格式(参考)附件十二", - "商务要求“★”号条款响应、偏离说明表": "第七章投标文件格式(参考)附件十三", - "技术、服务要求响应、偏离说明表": "第七章投标文件格式(参考)附件十五", - "技术、服务要求“★”号条款响应、偏离说明表": "第七章投标文件格式(参考)附件十六", - "偏离项的具体要求": "未知" - }, - "踏勘现场": "不组织", - "货物列表": {} - } - } + "资格性审查": { + "1": "供应商应具备《政府采购法》第二十二条规定的条件,提供相关材料。", + "2": "法人或者其他组织的营业执照等证明文件,自然人的身份证明;", + "3": "财务状况报告,依法缴纳税收和社会保障资金的声明函;", + "4": "具备履行合同所必需的设备和专业技术能力的证明材料;", + "5": "未被列入信用记录名单声明函;", + "6": "参加政府采购活动前 3年内在经营活动中没有重大违法记录的书面声明;", + "7": "具备法律、行政法规规定的其他条件的证明材料;", + "8": "招标文件第一章“投标人资格要求”中有特殊要求的,投标人应提供其符合特殊要求的证明材料或者情况说明;", + "9.1.1": "未被列入信用记录名单声明函;", + "10.1.1": "参加政府采购活动前 3年内在经营活动中没有重大违法记录的书面声明;", + "11": "具备法律、行政法规规定的其他条件的证明材料;", + "12": "招标文件第一章“投标人资格要求”中有特殊要求的,投标人应提供其符合特殊要求的证明材料或者情况说明;" + } } -res1,res2=post_process_baseinfo(data) -print(res1) \ No newline at end of file +res1=process_dict(preprocess_dict(data)) +print(json.dumps(res1,ensure_ascii=False,indent=4)) \ No newline at end of file diff --git a/flask_app/货物标/基础信息解析main.py b/flask_app/货物标/基础信息解析main.py index 2e64210..f924535 100644 --- a/flask_app/货物标/基础信息解析main.py +++ b/flask_app/货物标/基础信息解析main.py @@ -13,8 +13,8 @@ from flask_app.货物标.提取采购需求main import fetch_procurement_reqs def aggregate_basic_info_goods(baseinfo_list): - for i in baseinfo_list: - print(json.dumps(i,ensure_ascii=False,indent=4)) + # for i in baseinfo_list: + # print(json.dumps(i,ensure_ascii=False,indent=4)) """ 将基础信息列表中的数据进行合并和分类。 diff --git a/flask_app/货物标/截取pdf货物标版.py b/flask_app/货物标/截取pdf货物标版.py index ffb74dd..7c28cf1 100644 --- a/flask_app/货物标/截取pdf货物标版.py +++ b/flask_app/货物标/截取pdf货物标版.py @@ -230,99 +230,156 @@ def get_patterns_for_notice_twice(): # return start_page, mid_page, end_page def extract_pages_tobidders_notice(pdf_document, begin_pattern, begin_page, common_header, exclusion_pattern): - def run_extraction(): + """ + 从PDF文档中提取起始页、中间页和结束页。 + + 如果第一次提取失败,则使用新的 begin_pattern 和 end_pattern 重新提取。 + + 参数: + pdf_document (PDFDocument): 要处理的PDF文档对象。 + begin_pattern (str 或 re.Pattern): 用于识别起始的正则表达式模式。 + begin_page (int): 开始搜索的页码。 + common_header (str): 每页需要清理的公共头部文本。 + exclusion_pattern (str 或 re.Pattern): 用于排除某些页的模式。 + + 返回: + tuple: (start_page, mid_page, end_page) 如果成功,否则 (None, None, None) + """ + + def run_extraction(local_begin_pattern, local_end_pattern=None): + """ + 使用提供的 begin 和 end 模式运行提取过程。 + + 如果未提供 local_end_pattern,则根据匹配的章节类型动态生成 end_pattern。 + + 参数: + local_begin_pattern (str 或 re.Pattern): 用于识别起始的正则表达式模式。 + local_end_pattern (str 或 re.Pattern, 可选): 用于识别结束的正则表达式模式。 + + 返回: + tuple: (start_page, mid_page, end_page) + """ start_page = None mid_page = None end_page = None chapter_type = None # 用于存储“章”或“部分” + combined_mid_pattern = None # 中间页的组合模式 for i, page in enumerate(pdf_document.pages): text = page.extract_text() or "" cleaned_text = clean_page_content(text, common_header) + # 如果已经找到中间页,且当前页匹配排除模式,则跳过 if exclusion_pattern and re.search(exclusion_pattern, cleaned_text) and mid_page is not None: continue + # 识别起始页 if start_page is None: - match = re.search(begin_pattern, cleaned_text) + match = re.search(local_begin_pattern, cleaned_text) if match and i > begin_page: start_page = i matched_text = match.group(0) # 获取整个匹配的文本 - if '章' in matched_text: - chapter_type = '章' - elif '部分' in matched_text: - chapter_type = '部分' - else: - chapter_type = None # 未匹配到“章”或“部分” - if chapter_type: - # 根据 chapter_type 动态生成 end_pattern - end_pattern = re.compile( - rf'^第[一二三四五六七八九十百千]+?(?:{chapter_type})\s*[\u4e00-\u9fff]+', - re.MULTILINE - ) - # print(f"动态生成的 end_pattern: {end_pattern.pattern}") # 打印生成的 end_pattern - - # 根据 chapter_type 动态生成 additional_mid_pattern - if chapter_type == '章': - additional_mid_pattern = r'^第[一二三四五六七八九十百千]+?(?:部分)' - elif chapter_type == '部分': - additional_mid_pattern = r'^第[一二三四五六七八九十百千]+?(?:章)' + # 如果未提供固定的 end_pattern,则根据匹配的章节类型动态生成 + if not local_end_pattern: + if '章' in matched_text: + chapter_type = '章' + elif '部分' in matched_text: + chapter_type = '部分' else: - additional_mid_pattern = '' + chapter_type = None # 未匹配到“章”或“部分” - # 定义基础的 mid_pattern - base_mid_pattern = r'^\s*(?:[((]\s*[一二12]?\s*[))]\s*[、..]*|[一二12][、..]+|[、..]+)\s*(说\s*明|总\s*则)' - - # 合并基础模式和额外模式 - if additional_mid_pattern: - combined_mid_pattern = re.compile( - rf'(?:{base_mid_pattern})|(?:{additional_mid_pattern})', + if chapter_type: + # 根据 chapter_type 动态生成 end_pattern + end_pattern_dynamic = re.compile( + rf'^第[一二三四五六七八九十百千]+?(?:{chapter_type})\s*[\u4e00-\u9fff]+', re.MULTILINE ) + + # 根据 chapter_type 动态生成 additional_mid_pattern + if chapter_type == '章': + additional_mid_pattern = r'^第[一二三四五六七八九十百千]+?(?:部分)' + elif chapter_type == '部分': + additional_mid_pattern = r'^第[一二三四五六七八九十百千]+?(?:章)' + else: + additional_mid_pattern = '' + + # 定义基础的 mid_pattern + base_mid_pattern = r'^\s*(?:[((]\s*[一二12]?\s*[))]\s*[、..]*|' \ + r'[一二12][、..]+|[、..]+)\s*(说\s*明|总\s*则)' + + # 合并基础模式和额外模式 + if additional_mid_pattern: + combined_mid_pattern = re.compile( + rf'(?:{base_mid_pattern})|(?:{additional_mid_pattern})', + re.MULTILINE + ) + else: + combined_mid_pattern = re.compile( + rf'{base_mid_pattern}', + re.MULTILINE + ) else: + # 如果未匹配到“章”或“部分”,使用默认的 end_pattern 和 mid_pattern + end_pattern_dynamic = re.compile( + r'^第[一二三四五六七八九十百千]+(?:章|部分)\s*[\u4e00-\u9fff]+', + re.MULTILINE + ) + + # 定义基础的 mid_pattern + base_mid_pattern = r'^\s*(?:[((]\s*[一二12]?\s*[))]\s*[、..]*|' \ + r'[一二12][、..]+|[、..]+)\s*(说\s*明|总\s*则)' combined_mid_pattern = re.compile( rf'{base_mid_pattern}', re.MULTILINE ) - # print(f"生成的 combined_mid_pattern: {combined_mid_pattern.pattern}") # 打印 combined_mid_pattern else: - # 如果未匹配到“章”或“部分”,使用默认的 end_pattern 和 mid_pattern - end_pattern = re.compile( - r'^第[一二三四五六七八九十百千]+(?:章|部分)\s*[\u4e00-\u9fff]+', - re.MULTILINE - ) - print(f"使用默认的 end_pattern: {end_pattern.pattern}") # 打印默认的 end_pattern - - # 定义基础的 mid_pattern - base_mid_pattern = r'^\s*(?:[((]\s*[一二12]?\s*[))]\s*[、..]*|[一二12][、..]+|[、..]+)\s*(说\s*明|总\s*则)' + # 如果提供了固定的 end_pattern,则使用默认的 mid_pattern + base_mid_pattern = r'^\s*(?:[((]\s*[一二12]?\s*[))]\s*[、..]*|' \ + r'[一二12][、..]+|[、..]+)\s*(说\s*明|总\s*则)' combined_mid_pattern = re.compile( rf'{base_mid_pattern}', re.MULTILINE ) - print( - f"使用默认的 combined_mid_pattern: {combined_mid_pattern.pattern}") # 打印默认的 combined_mid_pattern - continue + # 识别中间页 if start_page is not None and mid_page is None and combined_mid_pattern: if re.search(combined_mid_pattern, cleaned_text): mid_page = i - if start_page is not None and mid_page is not None and chapter_type: - if re.search(end_pattern, cleaned_text): + + # 识别结束页 + if start_page is not None and mid_page is not None: + # 使用提供的 end_pattern 或动态生成的 end_pattern + current_end_pattern = local_end_pattern if local_end_pattern else end_pattern_dynamic + if re.search(current_end_pattern, cleaned_text): if i > mid_page: end_page = i break return start_page, mid_page, end_page - # 运行提取 - start_page, mid_page, end_page = run_extraction() + # 第一次提取尝试,使用初始的 begin_pattern + start_page, mid_page, end_page = run_extraction(begin_pattern) + + # 如果第一次提取失败,则使用新的 begin_pattern 和 end_pattern 重新提取 + if not (start_page and mid_page and end_page): + # 定义新的 begin_pattern 和 end_pattern + new_begin_pattern = re.compile( + r'.*(?:投标人|磋商|供应商|谈判供应商|磋商供应商)须知\s*$|' + r'(?:一\s*、\s*)?(?:投标人?|磋商|供应商)须知前附表', + re.MULTILINE + ) + new_end_pattern = re.compile( + r'第[一二三四五六七八九十百千]+(?:章|部分)\s*[\u4e00-\u9fff、]+\s*$', + re.MULTILINE + ) + # 第二次提取尝试,使用新的模式 + start_page, mid_page, end_page = run_extraction(new_begin_pattern, new_end_pattern) return start_page, mid_page, end_page - def extract_pages_twice_tobidders_notice(pdf_path, output_folder, output_suffix, common_header): begin_pattern = re.compile( r'^第[一二三四五六七八九十百千]+(?:章|部分)\s*(?:(?:投标人?|磋商|供应商|谈判供应商|磋商供应商)须知)+' @@ -674,7 +731,7 @@ def truncate_pdf_specific_goods(pdf_path, output_folder, selections,unique_id="1 # TODO:交通智能系统和招标(1)(1)文件有问题 包头 绍兴 资格审查文件可能不需要默认与"evaluation"同一章 无效投标可能也要考虑 “more”的情况,类似工程标 唐山投标只有正文,没有附表 if __name__ == "__main__": - input_path = "C:\\Users\\Administrator\\Desktop\\new招标文件\\货物标\\HBDL-2024-0498-001-招标文件.pdf" + input_path = "C:\\Users\\Administrator\\Desktop\\new招标文件\\货物标\\HBDL-2024-0519-001-招标文件.pdf" # input_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\b151fcd0-4cd8-49b4-8de3-964057a9e653\\ztbfile.pdf" # input_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfiles" # input_path = "C:\\Users\\Administrator\\Desktop\\货物标\\output1\\2-招标文件_procurement.pdf" @@ -685,6 +742,6 @@ if __name__ == "__main__": # selections = [1,4] # files=truncate_pdf_specific_goods(input_path,output_folder,selections) print(files) - # selection = 2# 例如:1 - 公告, 2 - 评标办法, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求 + # selection = 4# 例如:1 - 公告, 2 - 评标办法, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求 # generated_files = truncate_pdf_main(input_path, output_folder, selection) # print(generated_files) \ No newline at end of file diff --git a/flask_app/货物标/无效标和废标和禁止投标整合main.py b/flask_app/货物标/无效标和废标和禁止投标整合main.py index e7ac017..bbc2c0d 100644 --- a/flask_app/货物标/无效标和废标和禁止投标整合main.py +++ b/flask_app/货物标/无效标和废标和禁止投标整合main.py @@ -516,11 +516,10 @@ if __name__ == '__main__': start_time = time.time() # truncate_json_path = "C:\\Users\\Administrator\\Desktop\\货物标\\output4\\tmp2\\竞争性谈判文件(3)_tobidders_notice_part1\\truncate_output.json" # truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output4\\招标文件(实高电子显示屏)_tobidders_notice_part1.docx" - clause_path = "D:\\flask_project\\flask_app\\static\\output\\015d997e-c32c-49d1-a611-a2e817ace6a1\\clause1.json" + clause_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\77a48c63-f39f-419b-af2a-7b3dbf41b70b\\clause1.json" # doc_path="C:\\Users\\Administrator\\Desktop\\货物标\\zbfilesdocx\\磋商文件(1).docx" - - doc_path = 'C:\\Users\\Administrator\\Desktop\\fsdownload\\a091d107-805d-4e28-b8b2-0c7327737238\\ztbfile.docx' - output_dir = "C:\\Users\\Administrator\\Desktop\\fsdownload\\a091d107-805d-4e28-b8b2-0c7327737238\\tmp" + doc_path = 'D:\\flask_project\\flask_app\\static\\output\\output1\\77a48c63-f39f-419b-af2a-7b3dbf41b70b\\ztbfile.docx' + output_dir = "D:\\flask_project\\flask_app\\static\\output\\output1\\77a48c63-f39f-419b-af2a-7b3dbf41b70b" results = combine_find_invalid(doc_path, output_dir) end_time = time.time() print("Elapsed time:", str(end_time - start_time)) diff --git a/flask_app/货物标/资格审查main.py b/flask_app/货物标/资格审查main.py index 666aa2a..ab57c5c 100644 --- a/flask_app/货物标/资格审查main.py +++ b/flask_app/货物标/资格审查main.py @@ -6,7 +6,7 @@ from flask_app.general.通义千问long import upload_file from flask_app.general.多线程提问 import multi_threading from flask_app.general.json_utils import clean_json_string from flask_app.货物标.投标人须知正文条款提取成json文件货物标版 import convert_clause_to_json - +import copy # 这个字典可能有嵌套,你需要遍历里面的键名,对键名作判断,而不是键值,具体是这样的:如果处于同一层级的键的数量>1并且键名全由数字或点号组成。那么就将这些序号键名全部删除,重新组织成一个字典格式的数据,你可以考虑用字符串列表来保持部分平级的数据 # 对于同级的键,如果数量>1且键名都统一,那么将键名去掉,用列表保持它们的键值 @@ -87,8 +87,16 @@ def process_dict(data): # 处理数字键,将其值递归处理后放入 'items' 列表中 if numeric_keys: + def sort_key(item): + key = item[0] + if re.match(r'^\d+$', key): # 纯整数 + return (int(key),) + elif re.match(r'^\d+\.\d+$', key): # 单层小数点 + return (float(key),) + else: # 多层序号,按字符串处理 + return tuple(map(int, key.split('.'))) # 按键排序,确保顺序一致 - numeric_keys_sorted = sorted(numeric_keys, key=lambda x: x[0]) + numeric_keys_sorted = sorted(numeric_keys, key=sort_key) result['items'] = [process_dict(item[1]) for item in numeric_keys_sorted] # 处理非数字键 @@ -136,7 +144,7 @@ def find_chapter_clause_references(data, parent_key=""): exclude_list = ["格式要求"] result = [] # 正则匹配"第x章"或"第x款" - chapter_clause_pattern = re.compile(r'第[一二三四五六七八九十\d]+[章款]') + chapter_clause_pattern = re.compile(r'第[一1]+[章款]|公告|邀请') # 如果数据不是字典,则直接返回空列表 if not isinstance(data, dict): return result @@ -162,8 +170,9 @@ def find_chapter_clause_references(data, parent_key=""): result.extend(find_chapter_clause_references(item, new_parent_key)) elif isinstance(value, str): # 如果值是字符串,检查是否匹配"第x章"或"第x款" - if chapter_clause_pattern.search(value): - result.append({full_key: value}) + if chapter_clause_pattern.search(value): #符合|应满足|详见 + if "符合"in value or "满足" in value or "详见" in value: + result.append({full_key: value}) return result @@ -202,7 +211,7 @@ def preprocess_value(value): if target_part: # 删除开头的"符合"或"应满足" - target_part = re.sub(r'^(符合|应满足)\s*', '', target_part.strip()) + target_part = re.sub(r'^(符合|应满足|详见)\s*', '', target_part.strip()) return target_part # 如果没有找到特定章节或条款,返回原始值 @@ -325,6 +334,7 @@ def process_match_keys(match_keys, clause_path_file): # 处理如'符合本采购文件第一章第二款要求'的情况,跳转到指定地方摘取内容 def process_additional_queries(combined_res, match_keys, output_folder, notice_path, invalid_path): + # print(match_keys) """ 处理额外的查询并更新结果。 @@ -340,8 +350,8 @@ def process_additional_queries(combined_res, match_keys, output_folder, notice_p """ # 对于空的notice_path的情况,此处做了异常处理 clause2_path = convert_clause_to_json(notice_path, output_folder, 2) - updated_match_keys = process_match_keys(match_keys, clause2_path) - + new_match_keys = copy.deepcopy(match_keys) + updated_match_keys = process_match_keys(new_match_keys, clause2_path) if updated_match_keys != match_keys: form_response_dict = update_json_data(combined_res, updated_match_keys) else: @@ -372,10 +382,10 @@ def combine_qualification_review(invalid_path, output_folder, qualification_path "该招标文件中规定的符合性审查标准是怎样的?请以json格式给出,外层为'符合性审查',你的回答要与原文完全一致,不可擅自总结删减,也不要回答有关资格性审查的内容。" ] results = multi_threading(user_queries, "", file_id, 2) - combined_res = {} for _, response in results: if response: + # print(response) cleaned_data = clean_json_string(response) processed = process_dict(preprocess_dict(cleaned_data)) combined_res.update(processed) @@ -391,12 +401,12 @@ def combine_qualification_review(invalid_path, output_folder, qualification_path file_to_process = qualification_path combined_res = process_file(file_to_process) - match_keys = find_chapter_clause_references(combined_res, notice_path) + match_keys = find_chapter_clause_references(combined_res) if not match_keys: return {"资格审查": combined_res} - return process_additional_queries(combined_res, match_keys, output_folder, notice_path,invalid_path) + return process_additional_queries(combined_res, match_keys, output_folder, notice_path,invalid_path) #还要跳转到第一章 except Exception as e: print(f"Error in combine_qualification_review: {e}") @@ -407,11 +417,12 @@ def combine_qualification_review(invalid_path, output_folder, qualification_path # [{'资格性审查.资格要求': '符合本采购文件第一章第二款要求,并提供合格有效的证明材料'}, {'资格性审查.没有重大违法记录的书面声明': '是否提交参加政府采购活动前三年内在经营活动中没有重大违法记录的书面承诺或声明(格式要求详见本项目采购文件第六章相关格式要求)'}] if __name__ == "__main__": # qualification_path="C:\\Users\\Administrator\\Desktop\\货物标\\output3\\6.2定版视频会议磋商文件_qualification2.pdf" - output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\zboutpub" - # qualification_path = "C:\\Users\\Administrator\\Desktop\\货物标\\output3\\094定稿-湖北工业大学轻武器模拟射击设备采购项目招标文件_qualification2.pdf" - qualification_path = "" - notice_path = "C:\\Users\\Administrator\\Desktop\\货物标\\output5\\094定稿-湖北工业大学轻武器模拟射击设备采购项目招标文件_notice.pdf" + output_folder = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\tmp" + qualification_path = "C:\\Users\\Administrator\\Desktop\\货物标\\output3\\2-招标文件_qualification1.pdf" + # qualification_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_qualification2.pdf" + # notice_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile_notice.pdf" + notice_path="C:\\Users\\Administrator\\Desktop\\货物标\\output5\\2-招标文件_notice.pdf" # knowledge_name = "6.2视频会议docx" - invalid_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\3395fc1b-432d-407d-a872-fc35e8475aef\\ztbfile_invalid.pdf" + invalid_path = "D:\\flask_project\\flask_app\\static\\output\\output1\\6558a50a-13ea-4279-a5db-684935481c39\\ztbfile.pdf" res = combine_qualification_review(invalid_path,output_folder, qualification_path, notice_path) print(json.dumps(res, ensure_ascii=False, indent=4))