11.26 合并分支

This commit is contained in:
zy123 2024-11-26 10:24:16 +08:00
commit 7e71a0aadd
17 changed files with 547 additions and 645 deletions

View File

@ -0,0 +1,88 @@
# flask_app/ConnectionLimiter.py
import threading
import time
from functools import wraps
from flask import current_app, jsonify, g, request, Response, stream_with_context
class ExecutionTimeoutMonitor:
"""监控请求执行时间,超时后释放信号量"""
def __init__(self, timeout, semaphore):
self.timeout = timeout
self.semaphore = semaphore
self.is_timeout = False
self.thread = threading.Thread(target=self._monitor)
self.thread.daemon = True
def _monitor(self):
"""等待指定时间后标记为超时并释放信号量"""
time.sleep(self.timeout)
self.is_timeout = True
self.semaphore.release() # 超时后释放信号量
current_app.logger.error(f"请求执行时间超过 {self.timeout} 秒并被终止。")
def start(self):
self.thread.start()
class ConnectionLimiter:
def __init__(self, max_connections=1):
self.semaphore = threading.Semaphore(max_connections)
def require_connection_limit(timeout=900):
"""装饰器:确保路由使用连接限制,并监控请求执行时间"""
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
blueprint = request.blueprint
limiter = current_app.connection_limiters.get(blueprint, current_app.connection_limiters.get('default'))
if limiter is None:
current_app.logger.error(f"未为蓝图 '{blueprint}' 配置 ConnectionLimiter并且未设置默认限流器。")
return jsonify({'error': '服务器配置错误'}), 500
acquired = limiter.semaphore.acquire(blocking=True)
if not acquired:
current_app.logger.warning("并发连接过多")
return jsonify({'error': '并发连接过多'}), 429
# 启动执行超时监控器
monitor = ExecutionTimeoutMonitor(timeout, limiter.semaphore)
monitor.start()
# 将限流器和监控器存储在 g 中,以便在 teardown_request 中释放信号量
g.limiter = limiter
g.monitor = monitor
try:
result = f(*args, **kwargs)
if isinstance(result, Response):
# 对于普通的 Response 对象,不需要额外处理
return result
elif hasattr(result, '__iter__'):
# 如果返回的是生成器,按原有逻辑处理
@stream_with_context
def generator_wrapper():
try:
for item in result:
if monitor.is_timeout:
current_app.logger.error("请求执行时间超过限制并被终止。")
break
yield item
finally:
if not monitor.is_timeout:
limiter.semaphore.release()
return Response(generator_wrapper(), mimetype='text/event-stream')
else:
# 对于其他类型的响应,直接返回
return result
except Exception as e:
limiter.semaphore.release()
current_app.logger.error(f"路由处理异常: {e}")
return jsonify({'error': '内部服务器错误'}), 500
return wrapped
return decorator

View File

@ -268,7 +268,7 @@ def multi_threading(queries, knowledge_name="", file_id="", llm_type=1):
with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor:
future_to_query = {}
for index, query in enumerate(queries):
time.sleep(0.5) # 每提交一个任务后等待0.5秒
time.sleep(0.7) # 每提交一个任务后等待0.5秒
future = executor.submit(llm_call, query, knowledge_name, file_id, result_queue, index, llm_type)
future_to_query[future] = index
retry_counts[index] = 0 # 初始化重试次数
@ -286,6 +286,7 @@ def multi_threading(queries, knowledge_name="", file_id="", llm_type=1):
except Exception as exc:
print(f"Query {index} generated an exception: {exc}")
retry_counts[index] += 1 # 增加重试计数
#Query 0 generated an exception: Error code: 429 - {'error': {'message': 'You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://help.aliyun.com/zh/dashscope/developer-reference/tongyi-thousand-questions-metering-and-billing.', 'type': 'insufficient_quota', 'param': None, 'code': 'insufficient_quota'}, 'request_id': 'de10e2e9-78c2-978f-8801-862ffb0892e9'}
if retry_counts[index] <= max_retries:
print(f"Retrying query {index} (attempt {retry_counts[index]})...")
print("重试的问题:" + queries[index])

View File

@ -38,25 +38,31 @@ def prepare_for_zige_info(zige_review):
# 检查是否存在"资格性和符合性审查"
if "资格性和符合性审查" in zige_review:
# 情况3只有"申请人资格要求"和"资格性和符合性审查"
if zige_review.get("申请人资格要求", {}) or zige_review.get("资格性和符合性审查", {}):
zigefuhe_info = json.dumps({
"申请人资格要求": zige_review.get("申请人资格要求", "未提供"),
"资格性和符合性审查": zige_review.get("资格性和符合性审查", "未提供")
"申请人资格要求": zige_review.get("申请人资格要求", {}),
"符合性审查": zige_review.get("资格性和符合性审查", {})
}, ensure_ascii=False, indent=4)
else:
# 情况1和2存在分开的资格审查和符合性审查
if zige_review.get("申请人资格要求", {}) or zige_review.get("资格性审查", {}):
zige_info = json.dumps({
"申请人资格要求": zige_review.get("申请人资格要求", "未提供"),
"资格性审查": zige_review.get("资格性审查", "未提供")
"申请人资格要求": zige_review.get("申请人资格要求", {}),
"资格性审查": zige_review.get("资格性审查", {})
}, ensure_ascii=False, indent=4)
# 处理符合性审查的两种可能的键名
# 检查符合性审查的键值是否为空
fuhe_key = "符合性审查" if "符合性审查" in zige_review else "符合性审查(以下情况不得出现)"
if zige_review.get(fuhe_key, {}):
fuhe_info = json.dumps({
fuhe_key: zige_review.get(fuhe_key, "未提供")
"符合性审查": zige_review.get(fuhe_key, {})
}, ensure_ascii=False, indent=4)
return zige_info,fuhe_info,zigefuhe_info
return zige_info, fuhe_info, zigefuhe_info
except KeyError as e:
print(f"缺少关键字: {e}")
# 异常时直接返回空字符串
return "", "", ""
def extract_zige_deviation_table(zige_info, fuhe_info, zigefuhe_info):
prompt_template1 = """
任务给出一份文本根据文本提取资格性检查的具体评审标准
@ -122,22 +128,31 @@ def extract_zige_deviation_table(zige_info, fuhe_info, zigefuhe_info):
zigefuhe_deviation = clean_json_string(model_res3)
result["资格审查"] = zigefuhe_deviation
else:
# 使用原有逻辑处理分开的资格审查和符合性审查
user_query1 = prompt_template1.format(full_text=zige_info)
user_query2 = prompt_template2.format(full_text=fuhe_info)
# 使用 ThreadPoolExecutor 并行执行两个模型调用
zige_deviation = {}
fuhe_deviation = {}
# 提交 zige_info 和 fuhe_info 的模型调用
with concurrent.futures.ThreadPoolExecutor() as executor:
future1 = executor.submit(get_model_response, user_query1)
future2 = executor.submit(get_model_response, user_query2)
model_res1 = future1.result()
model_res2 = future2.result()
zige_deviation = clean_json_string(model_res1)
fuhe_deviation = clean_json_string(model_res2)
futures = {}
if zige_info != "":
user_query1 = prompt_template1.format(full_text=zige_info)
futures["zige"] = executor.submit(get_model_response, user_query1)
if fuhe_info != "":
user_query2 = prompt_template2.format(full_text=fuhe_info)
futures["fuhe"] = executor.submit(get_model_response, user_query2)
# 获取结果
for key, future in futures.items():
try:
model_res = future.result()
if key == "zige":
zige_deviation = clean_json_string(model_res)
elif key == "fuhe":
fuhe_deviation = clean_json_string(model_res)
except Exception as e:
print(f"Error processing {key}: {e}")
# 合并结果
result["资格审查"] = {
**zige_deviation,
**fuhe_deviation
"资格性检查": zige_deviation.get("资格性检查", zige_deviation),
"符合性检查": fuhe_deviation.get("符合性检查", fuhe_deviation),
}
return result
def extract_business_deviation(procurement):

View File

@ -98,35 +98,48 @@ def preprocess_files(output_folder, downloaded_file_path, file_type,unique_id,lo
# 基本信息
def fetch_project_basic_info(invalid_path, merged_baseinfo_path, merged_baseinfo_path_more,tobidders_notice, clause_path, logger):
def fetch_project_basic_info(invalid_path, merged_baseinfo_path, merged_baseinfo_path_more, tobidders_notice, clause_path, logger):
logger.info("starting 基础信息...")
start_time = time.time()
try:
if not merged_baseinfo_path:
merged_baseinfo_path = invalid_path
if not merged_baseinfo_path_more:
merged_baseinfo_path_more=invalid_path
merged_baseinfo_path_more = invalid_path
if not tobidders_notice:
tobidders_notice = invalid_path
basic_res = combine_basic_info(merged_baseinfo_path,merged_baseinfo_path_more,tobidders_notice, clause_path)
basic_res = combine_basic_info(merged_baseinfo_path, merged_baseinfo_path_more, tobidders_notice, clause_path)
result = basic_res
except Exception as exc:
logger.error(f"Error in 基础信息: {exc}")
# 返回默认值
result = {"基础信息": {}}
end_time = time.time()
logger.info(f"基础信息 done耗时{end_time - start_time:.2f}")
return basic_res
return result
# 形式、响应、资格评审
def fetch_qualification_review(evaluation_method, qualification, output_folder, tobidders_notice_table, clause_path, invalid_path, merged_baseinfo_path,notice_path,logger):
def fetch_qualification_review(evaluation_method, qualification, output_folder, tobidders_notice_table, clause_path, invalid_path, merged_baseinfo_path, notice_path, logger):
logger.info("starting 资格审查...")
start_time = time.time()
try:
if not notice_path:
notice_path=invalid_path
notice_path = invalid_path
if not evaluation_method:
evaluation_method = invalid_path
if not merged_baseinfo_path:
merged_baseinfo_path = invalid_path
review_standards_res = combine_review_standards(evaluation_method, qualification, output_folder, tobidders_notice_table, clause_path, invalid_path, merged_baseinfo_path,notice_path)
review_standards_res = combine_review_standards(
evaluation_method, qualification, output_folder, tobidders_notice_table, clause_path, invalid_path, merged_baseinfo_path, notice_path
)
result = review_standards_res
except Exception as exc:
logger.error(f"Error in 资格审查: {exc}")
# 返回默认值
result = {"资格审查": {}}
end_time = time.time()
logger.info(f"资格审查 done耗时{end_time - start_time:.2f}")
return review_standards_res
return result
# 评分细则 流式
@ -147,38 +160,56 @@ def fetch_evaluation_standards(invalid_path, evaluation_method,logger):
# 无效、废标项解析
def fetch_invalid_requirements(invalid_docpath, output_folder,logger):
def fetch_invalid_requirements(invalid_docpath, output_folder, logger):
logger.info("starting 无效标与废标...")
start_time = time.time()
try:
find_invalid_res = combine_find_invalid(invalid_docpath, output_folder)
result = find_invalid_res
except Exception as exc:
logger.error(f"Error in 无效标与废标: {exc}")
# 返回默认值
result = {"无效标与废标": {}}
end_time = time.time()
logger.info(f"无效标与废标 done耗时{end_time - start_time:.2f}")
return find_invalid_res
return result
# 投标文件要求
def fetch_bidding_documents_requirements(invalid_path, merged_baseinfo_path_more,clause_path,logger):
def fetch_bidding_documents_requirements(invalid_path, merged_baseinfo_path_more, clause_path, logger):
logger.info("starting 投标文件要求...")
start_time = time.time()
try:
if not merged_baseinfo_path_more:
merged_baseinfo_path_more=invalid_path
merged_baseinfo_path_more = invalid_path
selection = 1
fetch_bidding_documents_requirements_json = extract_from_notice(merged_baseinfo_path_more, clause_path, selection)
result = {"投标文件要求": fetch_bidding_documents_requirements_json}
except Exception as exc:
logger.error(f"Error in 投标文件要求: {exc}")
# 返回默认值
result = {"投标文件要求": {}}
end_time = time.time()
logger.info(f"投标文件要求 done耗时{end_time - start_time:.2f}")
return {"投标文件要求": fetch_bidding_documents_requirements_json}
return result
# 开评定标流程
def fetch_bid_opening(invalid_path, merged_baseinfo_path_more,clause_path,logger):
def fetch_bid_opening(invalid_path, merged_baseinfo_path_more, clause_path, logger):
logger.info("starting 开评定标流程...")
start_time = time.time()
try:
if not merged_baseinfo_path_more:
merged_baseinfo_path_more=invalid_path
merged_baseinfo_path_more = invalid_path
selection = 2
fetch_bid_opening_json = extract_from_notice(merged_baseinfo_path_more, clause_path, selection)
result = {"开评定标流程": fetch_bid_opening_json}
except Exception as exc:
logger.error(f"Error in 开评定标流程: {exc}")
# 返回默认值
result = {"开评定标流程": {}}
end_time = time.time()
logger.info(f"开评定标流程 done耗时{end_time - start_time:.2f}")
return {"开评定标流程": fetch_bid_opening_json}
return result
#分段返回
@ -226,7 +257,14 @@ def engineering_bid_main(output_folder, downloaded_file_path, file_type, unique_
except Exception as exc:
logger.error(f"Error processing {key}: {exc}")
yield json.dumps({'error': f'Error processing {key}: {str(exc)}'}, ensure_ascii=False)
if key == 'evaluation_standards':
# 返回默认的商务评分和技术评分
default_evaluation = {
'technical_standards': {"技术评分": ""},
'commercial_standards': {"商务评分": ""}
}
yield json.dumps(default_evaluation, ensure_ascii=False)
# yield json.dumps({'error': f'Error processing {key}: {str(exc)}'}, ensure_ascii=False)
#TODO:基本信息,判断是否这里,打勾逻辑取消了。
if __name__ == "__main__":

View File

@ -517,7 +517,7 @@ def truncate_pdf_multiple(input_path, output_folder, unique_id="123"):
base_file_name)
if merged_result:
truncate_files.append(merged_result)
logger.info(f"merged_baseinfo: 已生成合并文件: {merged_output_path}")
# logger.info(f"merged_baseinfo: 已生成合并文件: {merged_output_path}")
else:
truncate_files.append("") # 如果 merged_result 未生成,添加空字符串
logger.warning("merged_baseinfo: 未生成合并文件,因为没有找到需要合并的 PDF 文件。")

View File

@ -1,4 +1,5 @@
# flask_app/routes/get_deviation.py
import time
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
import json
@ -6,13 +7,11 @@ import os
from flask_app.main.download import download_file
from flask_app.general.post_processing import outer_post_processing
from flask_app.general.接口_技术偏离表 import get_tech_and_business_deviation
from flask_app.logger_setup import CSTFormatter
from flask_app.routes.utils import generate_deviation_response, validate_request
from flask_app.ConnectionLimiter import require_connection_limit
get_deviation_bp = Blueprint('get_deviation', __name__)
@get_deviation_bp.route('/get_deviation', methods=['POST'])
@require_connection_limit(timeout=700)
def get_deviation():
logger = g.logger
unique_id = g.unique_id

View File

@ -1,9 +1,10 @@
# flask_app/routes/little_zbparse.py
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
import json
import os
from flask import Blueprint, request, jsonify, Response, g
from flask_app.ConnectionLimiter import require_connection_limit
from flask_app.main.download import download_file
from flask_app.general.post_processing import outer_post_processing
from flask_app.general.接口_小解析 import little_parse_main
@ -13,7 +14,9 @@ from flask_app.logger_setup import CSTFormatter
from flask_app.routes.utils import validate_request
little_zbparse_bp = Blueprint('little_zbparse', __name__)
@little_zbparse_bp.route('/little_zbparse', methods=['POST'])
@require_connection_limit(timeout=300)
def little_zbparse():
logger = g.logger
file_url, zb_type = validate_request()

View File

@ -1,5 +1,4 @@
# flask_app/routes/upload.py
from flask import Blueprint, request, jsonify, Response, stream_with_context, g
import json
import os
@ -12,28 +11,33 @@ from flask_app.general.post_processing import outer_post_processing
from flask_app.general.接口_技术偏离表 import get_tech_and_business_deviation
from flask_app.routes.utils import generate_deviation_response, validate_request
from flask_app.logger_setup import CSTFormatter
from flask_app.ConnectionLimiter import require_connection_limit
upload_bp = Blueprint('upload', __name__)
@upload_bp.route('/upload', methods=['POST'])
@require_connection_limit(timeout=800)
def zbparse():
logger = g.logger
logger.info("zbparse start!!!")
try:
logger.info("大解析开始!!!")
received_data = request.get_json()
logger.info("Received JSON data: " + str(received_data))
validation = validate_request()
if isinstance(validation, tuple) and len(validation) == 2 and isinstance(validation[0], str):
file_url, zb_type = validation
else:
return validation # 错误响应
try:
logger.info("starting parsing url:" + file_url)
return Response(stream_with_context(process_and_stream(file_url, zb_type)), content_type='text/event-stream')
return process_and_stream(file_url, zb_type)
except Exception as e:
logger.error('Exception occurred: ' + str(e))
return jsonify({'error': str(e)}), 500
except Exception as e:
logger.error('Unexpected exception: ' + str(e))
return jsonify({'error': 'Internal server error'}), 500
def process_and_stream(file_url, zb_type):
"""
下载文件并进行处理支持工程标和货物标的处理

View File

@ -1,5 +1,9 @@
import json
from flask import request,jsonify
from functools import wraps
from flask import request, jsonify, current_app
def validate_request():
"""
验证请求中的JSON数据
@ -49,3 +53,30 @@ def generate_deviation_response(tech_deviation, tech_star_deviation, business_de
'data': json.dumps(business_star_deviation, ensure_ascii=False)
}
return tech_deviation_response, tech_deviation_star_response, zigefuhe_deviation_response, shangwu_deviation_response, shangwu_star_deviation_response
def require_connection_limit():
"""装饰器:确保路由使用连接限制,并正确处理生成器函数"""
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
limiter = getattr(current_app, 'connection_limiter', None)
if limiter is None:
current_app.logger.error("ConnectionLimiter 未初始化")
return jsonify({'error': 'Server configuration error'}), 500
acquired = limiter.semaphore.acquire(blocking=True)
if not acquired:
return jsonify({
'error': 'Server is busy. Please try again later.',
'code': 503
}), 503
generator = f(*args, **kwargs)
try:
for item in generator:
yield item
finally:
limiter.semaphore.release()
return wrapped
return decorator

View File

@ -1,15 +1,22 @@
# flask_app/start_up.py
import logging
from flask import Flask, request, jsonify
from flask import Flask, request, g
from flask_app.ConnectionLimiter import ConnectionLimiter
from flask_app.logger_setup import CSTFormatter, create_logger
from flask_app.routes.get_deviation import get_deviation_bp
from flask_app.routes.little_zbparse import little_zbparse_bp
from flask_app.routes.upload import upload_bp
from flask_app.routes.test_zbparse import test_zbparse_bp
class FlaskAppWithLimiter(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 初始化一个字典来存储每个蓝图的限流器
self.connection_limiters = {}
def create_app():
app = Flask(__name__)
app = FlaskAppWithLimiter(__name__)
# 设置日志的全局配置(如果需要)
handler = logging.StreamHandler()
@ -41,10 +48,20 @@ def create_app():
app.register_blueprint(little_zbparse_bp)
app.register_blueprint(upload_bp)
app.register_blueprint(test_zbparse_bp)
app.connection_limiters['upload'] = ConnectionLimiter(max_connections=7)
app.connection_limiters['get_deviation'] = ConnectionLimiter(max_connections=7)
app.connection_limiters['default'] = ConnectionLimiter(max_connections=10)
@app.teardown_request
def teardown_request(exception):
limiter = getattr(g, 'limiter', None)
monitor = getattr(g, 'monitor', None)
if limiter and not monitor.is_timeout:
limiter.semaphore.release()
return app
#TODO:培训要求、总体要求、进度要求、'建设要求'到技术要求中,归类到其他要求中
#TODO:接口设置排队
if __name__ == '__main__':
app = create_app()
app.run(debug=True, host='0.0.0.0', port=5001)

View File

@ -1,514 +1,185 @@
# -*- encoding:utf-8 -*-
import concurrent.futures
import json
import re
from collections import defaultdict
from flask_app.货物标.技术参数要求提取后处理函数 import extract_matching_keys
from flask_app.general.doubao import doubao_model
from flask_app.general.json_utils import clean_json_string
def extract_zige_deviation_table(zige_info, fuhe_info, zigefuhe_info):
prompt_template1 = """
任务给出一份文本根据文本提取资格性检查的具体评审标准
输出要求
1.以json格式返回结果不要输出其他内容
2.键名为"资格性检查"键值为字符串列表每个字符串为一条评审标准评审标准不分先后不要有序号标注
要求与指南
1. 评审标准是具体的内容不要返回诸如'本项目的特定资格要求:'这种标题性质且不能体现具体评审标准的内容
2. 若文本中存在相同或相似的表述仅需取其中一个作为键值中的一条即可
文本内容{full_text}
"""
prompt_template2 = """
任务给出一份文本根据文本提取符合性检查的具体评审标准
输出要求
1.以json格式返回结果不要输出其他内容
2.键名为"符合性检查"键值为字符串列表每个字符串为一条评审标准评审标准不分先后不要有序号标注
3.仔细检查你所选取的标准若发现这些标准实际上是在描述不允许出现的符合性审查情况则将外键替换为'符合性检查(以下情况不得出现)'并将这些标准写入其中
要求与指南
1. 评审标准应该是具体的内容不要返回诸如'本项目的特定符合性要求:'这种标题性质且不能体现具体评审标准的内容
2. 若文本中存在相同或相似的表述仅需取其中一个作为键值中的一条即可
输出示例1
{{
"符合性检查": [
"因素1",
"因素2",
...
]
}}
输出示例2
{{
"符合性检查(以下情况不得出现)": [
"因素1",
"因素2",
...
]
}}
文本内容{full_text}
"""
prompt_template3 = """
任务给出一份文本根据文本提取资格性检查和符合性检查的具体评审标准
输出要求
1.以json格式返回结果不要输出其他内容
2.键名为"资格性和符合性检查"键值为字符串列表每个字符串为一条评审标准评审标准不分先后不要有序号标注
要求与指南
1. 评审标准应该是具体的内容不要返回诸如'本项目的特定符合性要求:'这种标题性质且不能体现具体评审标准的内容
2. 若文本中存在相同或相似的表述仅需取其中一个作为键值中的一条即可
文本内容{full_text}
"""
def get_model_response(query):
return doubao_model(query)
result = {"资格审查": {}}
if zigefuhe_info:
# 如果zigefuhe_info非空使用prompt_template3
user_query3 = prompt_template3.format(full_text=zigefuhe_info)
model_res3 = get_model_response(user_query3)
zigefuhe_deviation = clean_json_string(model_res3)
result["资格审查"] = zigefuhe_deviation
else:
zige_deviation = {}
fuhe_deviation = {}
# 提交 zige_info 和 fuhe_info 的模型调用
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = {}
if zige_info != "":
user_query1 = prompt_template1.format(full_text=zige_info)
futures["zige"] = executor.submit(get_model_response, user_query1)
if fuhe_info != "":
user_query2 = prompt_template2.format(full_text=fuhe_info)
futures["fuhe"] = executor.submit(get_model_response, user_query2)
# 获取结果
for key, future in futures.items():
try:
model_res = future.result()
if key == "zige":
zige_deviation = clean_json_string(model_res)
elif key == "fuhe":
fuhe_deviation = clean_json_string(model_res)
except Exception as e:
print(f"Error processing {key}: {e}")
# 合并结果
result["资格审查"] = {
"资格性检查": zige_deviation.get("资格性检查", zige_deviation),
"符合性检查": fuhe_deviation.get("符合性检查", fuhe_deviation),
}
return result
a="""
"申请人资格要求": [
"1.满足《中华人民共和国政府采购法》第二十二条规定1具有独立承担民事责任的能力 2具有良好的商业信誉和健全的财务会计制度 3具有履行合同所必须的设备和专业技术能力 4有依法交纳税收和社会保障资金的良好记录 5参加政府采购活动前三年内在经营活动中没有重大违法记录 6法律、行政法规规定的其他条件。",
"2.单位负责人为同一人或者存在直接控股、管理关系的不同投标人,不得参加本项目同一合同 项下的政府采购活动。",
"3.未被列入“信用中国”网站(www.creditchina.gov.cn)失信被执行人、重大税收违法案件当事人名 单、政府采购严重违法失信名单和“中国政府采购”网站www.ccgp.gov.cn政府采购严重违法失信 行为记录名单(以磋商公告发布之日起查询结果为准)。",
"4.落实政府采购政策需满足的资格要求: 本项目(是/否)专门面向中小微型企业:否 。需落实的节能环保、中小微型企业扶持(含支 持监狱企业发展、促进残疾人就业)等相关政府采购政策详见磋商文件。"
],
"资格性审查": {
"资格要求": "符合本采购文件第一章第二款要求,并提供合格有效的证明材料。",
"其他要求": [
"符合竞争性磋商文件规定的其他要求",
"是否符合竞争性磋商采购文件中的其他规定"
],
"磋商报价": [
"每一种采购内容是否只有一个报价",
"报价金额是否超过采购预算"
],
"磋商书签字盖章": "是否有法定代表人或其委托代理人签字并加盖单位公章",
"磋商结果有效期": "投标有效期满足招标文件要求。",
"信誉情况": "无不良经济纠纷记录和违法行为的;",
"采购需求响应": [
"是否实质性响应采购文件采购技术要求的",
"是否有提出采购人不能接受的合同条件的"
]
}
"""
b="""
"符合性审查": {
"磋商报价": [
"每一种采购内容是否只有一个报价",
"报价金额是否超过采购预算"
],
"磋商书签字盖章": "是否有法定代表人或其委托代理人签字并加盖单位公章",
"磋商结果有效期": "投标有效期满足招标文件要求。",
"信誉情况": "无不良经济纠纷记录和违法行为的;",
"采购需求响应": [
"是否实质性响应采购文件采购技术要求的",
"是否有提出采购人不能接受的合同条件的"
],
"其他要求": "是否符合竞争性磋商采购文件中的其他规定"
}
"""
c=""
res=extract_zige_deviation_table(a,b,c)
print(json.dumps(res,ensure_ascii=False,indent=4))
data={
"多媒体会议厅设备": {
"LED屏显示设备": {
"户内全彩LED屏全彩高刷": [
"1.LED 封装形式: SMD2121 黑灯, 发光点颜色组合: 1R1G1B 。 2.物理点间距: 2.5mm 分辨率: 160000 点/m 2 刷新率≥60HZ。",
"3.P2.5 全彩屏:室内 P2.5 表贴三合一全彩屏,屏体显示面积 7.68 米(W)*4.32 米(H) m =33.17 平方米, 分辨率: 3072 点( W *1728 点( H 。 4.水平视角: 160 ° ; 垂直视角: 160 ° ; 刷新频率: 3840Hz 对比度: 10000 1 色温: 2000-10000K 可调 (提供第三方检测报告并加盖制造商公章) 。 5.像素失控点: ≤ 1/100000 且 无连续失控点, 亮度均匀性: ≥98% 色度均匀性: ±0.003Cx,Cy 之内。 6.防护等级: IP 5X 平均无故障时间: ≥60000H提供第三方检测报告并加盖制 造商公章) 。 7.视频信号: 兼容 PAL/NTSC/SECAM 制式, 支持 S-Video VGA RGB Composite Video SDI DVI RF RGBHV YUV YC 等。 8.控制方式: 同步控制; 驱动器件: 恒流; 换帧频率: ≥60Hz 扫描方式: 32S。 9.环境温度: 存储-35℃~+85℃ , 工作温度 10℃~+40℃。 10. ▲刷新率( Hz :≥3840 Hz (提供第三方检测报告并加盖制造商专用章) 。 11. ▲ LED 显示屏产品 PCB 采用多层电路板设计,表面沉金工艺,防火阻燃等级符 合 UL 94 V-0 级 提供第三方检测报告并加盖制造商 公章) 。 12. ▲LED 显示屏依据 BS476-7 测试标准, 产品检测合格, 符合 CLass 1 标准, 防 火等级达到 UL 94 V-0 级 提供第三方检测报告并加盖制造商公章) 。 13. ▲LED 显示屏生产商需提供 CCC 中国国家强制性产品认证证书, ROHS 证书, CB 证书复印件加盖生产商公章。 14. ▲显示屏产品必须提供 CE -EMC 、 CE -LVD 认证证书并提供 CE -EMC 、 CE -LVD 报告及符合性声明文件。 15. ▲生产企业需通过中国质量检验协会检验合格并提供全国质量检验稳定合格产 品证书复印件加盖生产商公章。 16. ▲生产厂家满足有害物质过程管理体系要求并通过 IECQ -QC -080000 符合性认 证, 提供证书复印件并加盖厂家公章。"
"申请人资格要求": [
"1.满足《中华人民共和国政府采购法》第二十二条规定1具有独立承担民事责任的能力 2具有良好的商业信誉和健全的财务会计制度 3具有履行合同所必须的设备和专业技术能力 4有依法交纳税收和社会保障资金的良好记录 5参加政府采购活动前三年内在经营活动中没有重大违法记录 6法律、行政法规规定的其他条件。",
"2.单位负责人为同一人或者存在直接控股、管理关系的不同投标人,不得参加本项目同一合同 项下的政府采购活动。",
"3.未被列入“信用中国”网站(www.creditchina.gov.cn)失信被执行人、重大税收违法案件当事人名 单、政府采购严重违法失信名单和“中国政府采购”网站www.ccgp.gov.cn政府采购严重违法失信 行为记录名单(以磋商公告发布之日起查询结果为准)",
"4.落实政府采购政策需满足的资格要求: 本项目(是/否)专门面向中小微型企业:否 。需落实的节能环保、中小微型企业扶持(含支 持监狱企业发展、促进残疾人就业)等相关政府采购政策详见磋商文件"
],
"发送盒": [
"1.支持 HDMI 和 DVI 视频信号输入及 HDMI 信号 LOO P 输出, 标准 60Hz 并可以自动适应帧率。",
"2.输入分辨率: 最大 1920*1200 点, 支持分辨率任意设置。",
"3.单卡最大带载面积: 230 万像素, 最宽可达 4096 点, 或最高可达 2560 点。",
"4.4 个千兆网口输出, 支持上下 、左右及混合型任意拼接。",
"5.双 USB 2.0 高速通讯接口, 用于电脑调试和卡间级联。",
"6.支持多发送器任意拼接级联, 严格同步。",
"7.支持亮度和色温调节。",
"8.支持 HDCP。",
"9.▲提供发送卡第三方检测报告并加盖制造商公章。"
"资格性审查": {
"资格要求": "符合本采购文件第一章第二款要求,并提供合格有效的证明材料。",
"其他要求": [
"符合竞争性磋商文件规定的其他要求",
"是否符合竞争性磋商采购文件中的其他规定"
],
"LED显示屏控制系统": [
"1.配置显示屏的性能参数, 如: LED 显示屏视觉刷新率, 灰度级数, 移位时钟频率等;",
"2.配置显示屏的传输方式和方向;",
"3.配置控制器映射位置和大小;",
"4.保存和加载控制系统参数;",
"5.周期刷新显示屏控制系统的工作状态;",
"6.读取显示屏校正系数, 手动调节显示屏的校正系数;",
"7.上传校正数据到控制系统;",
"8.配置显示屏的亮度调节模式, 设置每种模式对应的参数;",
"9.配置显示屏色温列表, 对显示屏进行色温调节;",
"10.对显示屏进行 Gamma 调节;",
"11.查看当前控制系统的映射信息 、版本信息, 并对控制器进行授权;",
"12.显示屏画面控制, 包括: 画面黑屏 、画面锁定 、正常显示;",
"▲ 13.为保证显示屏效果兼容性控制软件与控制系统 、显示屏为同一品牌, 需提供 LED 显示屏智慧控制系统软件著作权和软件测试报告的复印件加盖厂家公章。"
"磋商报价": [
"每一种采购内容是否只有一个报价",
"报价金额是否超过采购预算"
],
"视频处理器": [
"1.支持 4 口拼接,输出模式支持 520 万像素自定义输出,水平最大 15360 像素,纵向最大 6144 像素。",
"2.支持三画面任意布局、支持同时在屏幕上呈现 3 个或 3 个以下的画面,画面大小自由缩放 、摆放, 画面之间可相互叠加。",
"3.支持信号回显,可通过软件实时查看输入输出信号;支持同时进行多画面预览及输出监视, 支持同时预览 6 路输入信号, 并可以 同时监视当前的输出画面。",
"4.支持多组可编程全局图文叠加;支持信号及模式无缝切换,提供十多种过度特效, 包括淡入淡出, 无缝直切, 垂直 、水平梳理, 圆形切入 、切出, 菱形切入 、切出, 各个方向的划幕。",
"5.支持亮度抠像,支持指定亮度值以下的背景扣除,并融合到新的背景当中;支持 对每个画面的透明度进行单独调节, 支持 0~100%可调。",
"6.支持对画面的边缘进行羽化,可使叠加的画面能够更好地与背景画面融合、支持 画面冻结任意画面。",
"7.支持将图文字幕叠加到视频画面上的任意位置, 并可设定不同的运动轨 迹和速度。",
"8.支持一键输出黑屏信号, 可用于演艺活动场景; 支持保存 32 组不同的设置参数 保存为模式, 并可快速调用。",
"9.支持脱机的计划任务, 可设定定时操作, 完成 自动化管理。",
"10.输入信号: DVI-D × 1 、HDMI × 1 、VGA ×2 最大支持分辨率为 1920 × 1200@60Hz 向下兼容;",
"11.输入信号: CVBS ×2 NTSC/PAL 自适应。",
"12.输出信号: DVI-D ×5 支持常见输出分辨率, 如 2048 × 1152@60H z 1920 × 1080@60Hz支持自定义输出分辨率如 3840 ×660@60Hz支持 60Hz/50Hz/30Hz 输出帧率;兼容 HDMI 1.3 及以下版本其中4 路为变成输出,另 1 路为预览输出。",
"▲ 13.产品厂家具有服务能力达到 GB/T279 22-2011《商品售后服务评价体系》标准 五星级以及具有知识产权管理体系认证证书,提供证书复印件并盖生产厂商公章。"
],
"智能配电柜": [
"1.额定功率: 10KW 输出路数: 3 路",
"2.配电柜输入电压为交流 380V ± 15%,工频 50Hz。具有过压、浪涌、短路、过流、过载 、漏电等保护功能。",
"3. 内置避雷器, 具有避雷防雷功能。"
],
"台式电脑": [
"品牌商用机 I5/8G/ 120G SSD 1T/DVDRW/独显 2G/22"
],
"控制桌(定制)": []
},
"LED显示屏施工材料、技术服务费、包装费": {
"结构边框": [
"1. 室内钢结构设计,采用 Q235B 国标材料"
],
"线材(按需)": [],
"包装材料": [
"3|包装材料|3|㎡|"
"磋商书签字盖章": "是否有法定代表人或其委托代理人签字并加盖单位公章",
"磋商结果有效期": "投标有效期满足招标文件要求。",
"信誉情况": "无不良经济纠纷记录和违法行为的;",
"采购需求响应": [
"是否实质性响应采购文件采购技术要求的",
"是否有提出采购人不能接受的合同条件的"
]
},
"扩声系统": {
"主扩全频专业音箱": [
"1 阻抗: 8Ω",
"2 频响: 45Hz-20KHz",
"3 额定功率: 400W",
"4 灵敏度: 99dB/W/M",
"5 覆盖角度: (H)90 °(V)80 °",
"6 高音: 1.7\"压缩高音单元 × 1 低音: 12\"低音 × 1"
"符合性审查": {
"磋商报价": [
"每一种采购内容是否只有一个报价",
"报价金额是否超过采购预算"
],
"专业功放-1": [
"1.设备支持开机软启动支持高品质变压器和低阻大容量电解滤波内置30Hz/50Hz高通滤波器支持智能控制强制散热设计内置智能压限系统。",
"2.支持立体声或桥接、并行工作模式,输出功率支持立体声/并联8Ω×2:700W×2.立体声/并联4Ω×2:1050W×2.立体声/并联2Ω×2:1500W×2.桥接8Ω:2100W、桥接4Ω:3000W。",
"3.采用XLR/TRS接口输入接口支持过流保护、直流保护、短路保护等功能具有电源、保护、失真指示灯。",
"4.信噪比≥100dB、频响:20Hz-20KHz分离度≥80dB、失真度≤0.05%",
"▲5.提供全国质量检验稳定合格产品和全国质量信得过产品的证书复印件并加盖厂家公章"
"磋商书签字盖章": "是否有法定代表人或其委托代理人签字并加盖单位公章",
"磋商结果有效期": "投标有效期满足招标文件要求。",
"信誉情况": "无不良经济纠纷记录和违法行为的;",
"采购需求响应": [
"是否实质性响应采购文件采购技术要求的",
"是否有提出采购人不能接受的合同条件的"
],
"辅助专业音箱": [
"1 阻抗: 8Ω",
"2 频响: 45Hz-20KHz",
"3 额定功率: 300W",
"4 灵敏度: 98dB/W/M",
"5 覆盖角度: (H)90 °(V)80 °",
"6 高音: 1.7\"压缩高音单元 × 1 低音: 10\"低音 × 1"
],
"专业功放-2": [
"1.输出功率20Hz-20KHz/THD≤1立体声/并联8Ω×2500W×2、立体声/并联4Ω×2750W×2、立体声/并联2Ω×21125W×2、桥接8Ω1500W、桥接4Ω2200W",
"2.开机软启动,防止开机时向电网吸收大电流,干扰其它用电设备。",
"3.智能控制强制散热设计,风机噪音小,散热效率高等特点。",
"4.内置智能压限系统,控制功率模块及扬声器系统在安全范围内工作。",
"5.内置30Hz/50Hz高通滤波器。",
"6.多种模式:立体声、桥接、并行。",
"7.充沛储备功率可以带2R低阻输出高保真的音质完美还原音源品质可让演员发挥淋漓尽致。",
"8.高品质变压器和低阻大容量电解滤波,保证大动态工作应付自如。",
"9.H类高效的功率放大电路完善可靠的安全保护措施和工作状态指示短路、过载、直流和过热保护、变压器过热保护让用户放心使用。",
"10.连接座XLR、TRS接口"
],
"壁挂支架": [
"1. 固定面板尺寸 (长*宽) :240mm*130mm",
"2.臂杆长度:440mm",
"3.箱体固定杆长度:165mm"
],
"返听专业音箱": [
"1.阻抗: 8Ω",
"2.频响: 60Hz-20KHz",
"3.额定功率: 300W",
"4.灵敏度: 98dB/W/M",
"5.覆盖角度: (H)80 °(V)60 °",
"6.高音: 1.4\"压缩高音单元 × 1 低音: 10\"低音 × 1"
],
"返听专业功放": [
"1.两声道功放有三档输入灵敏度选择(支持 0.775V/1V/ 1.44V 可轻松接纳宽幅度范围信号源输入 。输入座接地脚接地和悬浮控制。",
"2.采用智能控制强制散热设计,具有风机噪音小,散热效率高等特点;具有完善可靠的安全保护措施和工作状态指示(短路 、过载 、直流和过热保护, 变压器 过热 保护 让用户放心使用。",
"3.输出功率:立体声/并联 8Ω:500W*2.立 体声/并联 4Ω:730W*2.桥接 8Ω:1460W 。",
"4.采用标准 XLR + TRS 1/4 ” 复合多功能输入接口, 更加方便不同用户需求 。智能 削峰限幅器, 控制功率模块及扬声器系统在安全范围内工作。",
"5.信噪比≥95dB、频响:20Hz-20KHz(+0dB/-2dB)分离度≥8 0dB、失真度≤0.05%",
"▲6.功放需要具备线路自动检测嵌入式集成功能,提供功放线路自动检测嵌入式集 成控制软件的软件著作权证书及软件检测报告的复印件加盖厂家公章。",
"▲7.功放需要具备管理及调试软件功能,提供功放管理模块软件和数字功 放调试软 件的软件著作权证书复印件加盖厂家公章。"
],
"超低频专业音箱": [
"1.阻抗: 8Ω",
"2.频响: 40Hz~2KHz",
"3.额定功率: 600W",
"4.灵敏度: 99dB/W/M",
"5.低音: 18\"低音 × 1"
],
"专业功放-3": [
"1.工业造型铝面板,专业设计坚固面耐用,面板防尘网可折洗结构设计。",
"2.开机软启动,防止开机时向电网吸收大电流,干扰其它用电设备。",
"3.智能控制强制散热设计连接座XLR、TRS接口。",
"4.内置智能压限系统,控制功率模块及扬声器系统在安全范围内工作。",
"5.输出功率20Hz-20KHz/THD≤1立体声/并联8Ω×2900W×2立体声/并联4Ω×21350W×2立体声/并联2Ω×22000W×2桥接8Ω2600W桥接4Ω4000W",
"6.多种模式:立体声、桥接、并行。",
"7.充沛储备功率可以带2R低阻输出高保真的音质完美还原音源品质可让演员发挥淋漓尽致。",
"8.高品质变压器和低阻大容量电解滤波,保证大动态工作应付自如。",
"9.H类高效的功率放大电路完善可靠的安全保护措施和工作状态指示短路、过载、直流和过热保护、变压器过热保护让用户放心使用。"
],
"音箱地插": [
"欧姆口*1"
],
"调音台": [
"1.支持≥10 路 MIC 输入兼容 8 路线路输入接口支持≥2 组立体声输入 接口, ≥4 路 RCA 输入, 话筒接口幻像电源: +48V。",
"2.具有≥2 组立体主输出 、≥4 路编组输出 、≥4 路辅助输出 、≥ 1 组立体声监听输 出 、 ≥ 1 个耳机监听输出 、 ≥2 个效果输出 、 ≥ 1 组主混音断点插入 、 ≥8 个断点 插入 。 (提供接口截图佐证)",
"3. 内置 24 位 DSP 效果器, 提供 100 种预 设效果。",
"4.具备 15 个 60mm行程的高精密碳膜推子。",
"▲5. 内置 USB 声卡模块, 支持连接电脑进行音乐播放和声音录音; 内置 MP 3 播放 器, 支持 1 个 USB 接口接 U 盘播放音乐。",
"6.频率响应20Hz-20kHz±2dB失真度<0.03% at+0dB,22Hz-22KHz A-weighted 灵敏度: +21dB~-30dB 信噪比: <-100dBr A-weigh ted",
"▲7.所投产品生产厂家的软件能力成熟度集成模型达到 CMMI 成熟度等级 3 级,提 供证书复印件并加盖厂家公章。"
],
"音频处理器": [
"1.数字音频处理器支持≥8 路平衡式话筒/线路输入通道,采用裸线接口端子,平衡接法; 支持≥8 路平衡式线路输出, 采用裸线接口端子, 平衡接法。",
"2.输入通道支持前级放大 、信号发生器 、扩展器 、压缩器 、5 段参量均衡 、 AM 自动混音功能 、 AFC 自适应反馈消除 、 AEC 回声消除 、 ANC 噪 声消除。",
"3.输出通道支持 31 段参量均衡器 、延时器 、分频器 、高低通滤波器 、 限幅器。",
"4.支持 24bit/48KHz 卓越的高品质声音, 支持输入通道 48V 幻像供电, 频率响 应: 20Hz-20KHz总谐波失真0.002% @ 1KHz ,4dBu数/模动态范围(A-计权)120dB 最大输出电平≥+24 dBu 最大输入电平≥+24 dBu 。",
"▲5.支持通过 ipad 或 iPhone 或安卓手机 APP 软件进行操作控制、切换 8 个不同场 景 。面板具备 USB 接口, 支持多媒体存储, 可进行播放或存储录播 。 (提供功能 演示视频供评标查证, 未提供本项演示的视为非实质性响 应)",
"6.配置双向 RS -232 接口, 可用于控制外部设备; 配置 RS -485 接口, 可实现自动 摄像跟踪功能 。配置 8 通道可编程 GPIO 控制接口 (可自定义 输入输出) 。",
"7.支持断电自动保护记忆功能。支持通道拷贝、粘贴、联控功能。支持通过浏览器 访问设备, 下载自带管理控制软件; 软件界面直观 、 图形化, 可工作在 XP/Windows7.8.10 等系统环境下。",
"▲8.提供音频处理器省级及以上认证中心的权威检测报告含以上功能内容的复印 件并加盖厂家公章。"
],
"抑制器": [
"1.采用 96KHz 采样频率, 32-bit DSP 处理器, 24-bitA/D 及 D/A 转换, 支持数字信号输入输出通道提供 coaxial AES 及光纤接口。",
"2.支持 144 x 32 的 LCD 显示屏显示参数功能, 提供 6 段 LED 显示输出电平; 每通道 24 个 LED 灯显示啸叫抑制状态数量;",
"3.每通道支持压缩、限幅、噪声门、功能设置,可切换工作模式为直通或反馈抑制;可任意编辑固定和动态反馈点数量,可一键清除啸叫点;单机可存储 30 组用户程序。"
],
"无线话筒": [
"1.采用 UHF 超高频段双真分集接收,并采用 PLL 锁相环多信道频率合成技术V/A 显示屏在任何角度观察字体清晰同时显示信道号与工作频率 。红外对频功能, 能 方便 、快捷的使发射机与接收机频率同步, 超强的抗干扰能力 能有效抑制由外部带来的噪音干扰及同频干扰。",
"2.带 8 级射频电平显示8 级音频电平显示,频道菜单显示,静音显示;具有 SCAN 自动扫频功能, 使用前按 SET 功能键自动找一个环境最干净的频点处停下来, 此 频率作为接收机的使用频率",
"3.平衡和非平衡两种选择输出端口, 适应不同的设备连接需求。",
"4.频率指标:640-830MHz 调制方式:宽带 FM 提供各 200 个可调频率, 共 500 个 信道选择,真正分集式接收,有效避免断频现象和延长接收距离。工作距离约 100m 中频丰富, 声音具有磁性感和混厚感。",
"5.接收机指标:采用二次变频超外差的接收机方式,灵敏度: 12dB μV80dBS/N) 灵敏度调节范围:12-32dB μV 频率响应:80Hz-18KHz ( ±3dB",
"6.系统包括有一台主机+两个无线手持话筒;发射机指标:音 头采用动圈式麦克风, 输出功率:3mW~30mW。",
"▲7.提供无线话筒控制软件和话筒呼叫控制软件的软件著作权证书及软件检测报告的复印件加盖厂家公章。"
],
"话筒呼叫控制嵌入软件": [
"1.软件内嵌于无线话筒系统设备, 话筒呼叫控制功能。",
"2.采用 UHF 超高频段双真分集接收, 并采用 PLL 锁相环多信道频率合成技术。",
"3.支持二次变频超外差接收机方式。",
"4.支持单独调节音量。",
"5.支持信道选择 、频率可调 、可设置主机与话筒配对。"
],
"话筒天线": [
"1.可支持为 4 台一拖二真分集话筒自动选讯接收机的多频道系统共用一对天线和一个电源, 简化天线装配工程, 提升接收距离及效能。",
"2.频带范围: 640~960MHz 输出/入增益+1.0dB(频段中心) 输出/入阻抗: 50Ω, 频宽: 320MHz。"
],
"有源监听音箱": [
"1.有源音箱内置高保真扬声器,额定输出功率支持 2 ×25W 支持 4-8Ω输出阻抗。",
"2.支持≥1 路话筒和≥1 路立体声线路 输入接口 、 1 路立体声线路输出接口, 带默 音功能,话筒优先于线路输入。具有 1 个麦克风音量调节1 个线路输入音量调节, 2 个高低音调节。",
"3.支持 100V 广播输入接口, 优先于本地广播。",
"4.具有输出过载 、过压 、短路保护。",
"5.信噪比≥70dB 频率响应 80Hz 16KHz 谐波失真≤ 1%"
],
"电源时序器": [
"1.支持 8 通道电源时序打开/关闭, 支持远程控制(上电+24V 直流信号) 8 通道电源时序打开/关闭—当电源开关锁处于 off 位置时有效。",
"2.当远程控制有效时同时控制后板 ALARM (报警) 端口导通—起到 级联控制 ALARM (报警) 功能。",
"3.单个通道最大负载功率 3500W 所有通道负载总功率达 6000W 输入连接器:大功率线码式电源连接器。",
"4.输出连接器: 4 个 16A 电源插座和 4 个 10A 电源插座。"
],
"天线分配器": [
"1.可支持为 4 台一拖二真分集话筒自动选讯接收机的多频道系统共用一对天线和一个电源, 简化天线装配工程, 提升接收距离及效能。",
"2.频带范围: 640~960MHz 输出/入增益+1.0dB(频段中心) 输出/入阻抗: 50Ω, 频宽: 320MHz。"
]
},
"辅助材料": {
"机柜": [
"1|机柜|2|套|"
],
"音频连接线-1": [
"1.8 米音频连接线:卡侬头(母)-卡侬头(公)"
],
"音频连接线-2": [
"5 米音频连接线3.5(耳机插头)-双 6.35 话筒插头"
],
"音频连接线-3": [
"1.8 米音频连接线6.35 话筒插头-卡侬头(公)"
],
"其它辅材(音箱线、电源线、网线、视频线等)": []
},
"会议座椅": {
"会议座椅": [
"▲ 1 、脚架材料为 2 mm 冷轧板板冲压成型, 表面经过喷涂处理, 脚架两边有侧板 覆盖侧板,侧板为 3m 中纤板尺寸为 395*355 mm ,面贴 3 mm 切割棉,表面再扪颐达礼堂椅高级布料。扶手面材料为橡木,尺寸为 415*85*28 mm 表面经过多次封闭漆处理, 观感亮丽, 颜色鲜艳, 木纹清晰 。扪布使用的胶 水为得力高环保胶水, 具有无色, 无味环保无有害物质的要求。",
"▲ 2 、座包回位方式为气杆弹簧慢回位, 座包内带铁框架铁, 框架尺寸为 425*430*60 mm , 座框架使用的材料为 1.5 mm 冷轧板 , 座框 架内带气杆,座外板尺寸 为 470*425*16 mm , 背外板材料为 16 mm 多层板, 表 面经过多次封闭漆处理, 观感 亮丽,颜色鲜艳,木纹清晰。座海绵尺寸为 4 80*465*150 mm 的冷发泡高密度定型 棉, 座内板为厚度 10 mm 的多层夹板, 座包表面 扪颐达礼堂椅高级布料, 胶水使 用得力高环保胶水。",
"▲ 3 、背包, 背海绵尺寸 700*490*140 mm 的 冷发泡高密度定型海绵, 背外板尺寸 为 750*510*16 mm , 背外板材料为 16 mm 多层板 表面经过多次封闭漆处理, 观感 亮丽, 颜色鲜艳, 木纹清晰 。背内板为厚度为 13 mm 的多层夹板, 背包表面扪颐 达礼堂椅高级布料, 胶水使用得力高环保胶水, 背包与脚架的连接 采用双背角码 连接, 是安装拆卸更方便。",
"▲ 4 、写字板为后置大弯刀铰链式后置写字板, 写 字板的尺寸为 480*300*16 mm 写字板材质为高密度板面贴防火板铝合金封边。",
"▲ 5 、座椅的下脚架壁厚为 2 mm 冷轧板,脚板尺寸为 310*70 mm , 脚孔距离 240 mm . 基本尺寸: 椅高: 1000±10 mm , 坐高 450±10 mm 背到座 760± 10 mm 背到写字板 860±10 mm 写字板高 600±10 mm 座深 450±10 mm 中心距 580±5 mm , 建议排距 为 900 mm "
]
},
"电动窗帘": {
"电动窗帘系统": [
"AC 110V-220V 50-60HZ 速度: 14CM/S 直轨含 4 米 全遮光窗帘"
]
"其他要求": "是否符合竞争性磋商采购文件中的其他规定"
}
},
"云平台及备课电脑": {
"备课一体机电脑": [
"1 、 ★机型: 品牌商用型一体台式计算机;",
"2、★显示器≥23.8 寸广视角全高清液晶显示屏1920x1080具备低蓝光功能保护视力 ",
"3 、 ▲CPU ≥ 六核 I5-9500 主频≥3.0GHz 缓存≥9MB",
"4 、主板: B360 芯片组或以上;",
"5 、 ▲内存: ≥8G DDR4 以上内存, 提供双内存槽位;",
"6 、显卡: 独立显卡;",
"7 、 ▲硬盘: ≥ 512G M.2 PCIe 固态硬盘, 支持扩展 7200 转机械硬盘;",
"8 、 网卡: 集成 10 100 1000M 以太网卡+802.11AC",
"9 、 ▲音频设备: 内置双立体声音箱, 支持杜比音效;",
"10 、键盘 、 鼠标: 无线键盘鼠标套件, 支持键盘开机功能, 方便使用;",
"11 、 ▲接口: ≥4 个 USB 3.1 G1 接口 、 1 个 U SB Type-C 接口 、 1 个 USB3.1Gen2 高 速接口 、 DP-In/Ount 二合一接口 、三合一读卡器 、 可选串口;",
"12 、 ▲电源: ≤ 150W 内置节能电源 并通过恶劣供电检验认证, 宽电压检验认证 可适应 90V 至 265V 的工作电压(提供认 证证书 ",
"13 、 ▲安全特性: USB 屏蔽技术, 仅识别 USB 键盘 、 鼠标, 无法识别其他 USB 读 取设备, 有效防止数据泄露 (提供实用截图 ",
"14 、▲机箱: 多功能平放式底座,支持屏幕俯仰、高度调整 、左右旋转,方便维护;",
"15.操作系统:出厂预装正版 Win10home 操作系统,每台机身均需粘贴正版 COA 标 贴, 微软正版可查;",
"16 、 ▲管理功能: 出厂预装正版远程管理软件, 如第三方软件, 需提供至少三年的 正版授权;支持 USB 端口管理、及时更新操作系统补丁、远程维护、限置网络带宽、 软/硬件资产统计等功能(需提供功能截图证明 ",
"17、服务 生产厂商三年保修服务,要求 7*24 全年无休2 小时响应服务, 厂家在 广水有售后服务网点并提供环保回收服务,提供商用大客户技术选线 400 或 800 售 后服务热线电话;",
"18. △供货要求: 提供全新未拆封的原厂原装新品, 生产日期为本项目招标后的最 新日期;"
],
"云平台管理软件": [
"▲ 1100 个云桌面系统 2 套。云桌面系统需提供满足教室所有桌面稳定运行的服务器详细配置方案 。可快速实现终端 PC 机的操作系统虚拟及应用环境虚拟 。整体集中控制 、集中管理 、快速高效 、安全可靠。",
"2 提供桌面云管理系统, 桌面云管理系统管理桌面更新模式, 桌面更新模式必须支持自动更新和手动更新(提供此功能界面截图证明)。",
"▲ 3 桌面虚拟化及终端平台软件支持全系统平台, Windows 系列 Windows 7 、 Windows10、WindowsServer2012、WindowsServer20162Linux 系列Fedora、Ubuntu、 CentOS。",
"4 为了避免工作期间系统更新影响业务, 桌面云管理平台提供 BT 服务端设置和 BT 客户端设置功能(提供此功能界面截图证明)。",
"5所有计算处理均由客户端本地进行 充分利用本地硬件资源(内存、 CPU 、显卡等)。能够流畅运行 AutoCAD 、Pro_E 、UG 、Catia 、3D Max 、视频制作 、 图像处理、 Voip 高清视频播放等大型应用, 亦可充分利用服务器缓存闲置资源。",
"6 采用了五级缓存机制(HDD/Memory/System/LocalDisk/LocalRAM) 大大的提高了服务器的性能和反应速度, 也延长了服务器硬盘的使用寿命, 减少系统维护的负担 (提供此功能界面截图证明)。",
"7 服务器采用树状结构存储镜像文件,单一镜像文件可同步提供上千个不同语言不同版本应用环境 。支持与 oralce 虚拟机 virtualbox 的数据迁移。",
"8 可 以针 对 每 个使 用 者 的虚 拟 磁盘 做 个 别的 IO 服 务器 分 流 及备 援 。 透过 ( DHCP , Boot , IO )管理及备援架构,真正达到了完美双机热备不停机的产品服务,完全 满足高端客户高可用性( High -Availability )的需求, 提供运行不中断的安全性和稳定性 。并支持多网卡负载均衡功能。",
"9 支持微软. vhd 虚拟盘格式, 最大的磁盘稳定性保证 、最好的系统兼容性保证 (Win732bit/64bit,2008R232bit/64bit) 、更可以让客户能建 立在微软强大的产品和技术 平台上面得到最大的保障(提供此功能界面截图证明)。",
"10 支持本地硬盘扇区缓存( LocaCache技术提高运行效率及安全性。全盘缓存支持还原模式和读写模式只写模式 3 种模式。",
"11 多重差异盘的功能, 可以依据不同客户需求来提供不同的虚拟硬盘, 让每个使用者都有专属的使用环境, 但又不会造成系统管理的负担 。可依使用者 &计算机等群组设定操作系统。",
"12 提供虚拟硬盘直接写入保存模式, 可以提供给每台客户端一个资料不还原,每次更新保留的个人化虚拟磁盘, 主要是用来保存一些个人的 系统环境和软件设置 ( UserProfile ) 满足使用者的个性化存储需求 。并支持手动备份和自动备份双模式功能。",
"13 服务器端镜像资源包存储以虚拟化方式, 实现多系统( Windows 、Linux 等)数据跨平台存储在镜像文件中, 并确保病毒无法感染服务端资源, 保障 服务端的安全性。"
],
"教学互动应用软件": [
"▲ 1 提供课程时间设置功能, 方便课程管理 (提供此功能界面截图证明)。",
"2 可按计划任务设定系统自维护策略和背景更新 (例如: 在指定的时间自动更新病毒库等软件)。",
"3 支持缓存服务器, 各分支机构, 分校, 可通过缓存服务器为客户端提供高性能的桌面服务",
"▲4 通过服务器, 远程修改客户端 IP 计算机名, 网关, 掩码 。(提供此功能界面截图证明)",
"5 具备支持创建任意多个管理员帐号, 并可自定义管理权限, 实现机房多人分级安全管理功能;通过 WEB 管理页面可以实现所有的管理操作 提供此功能界面截图证明)",
"6 为保障整体软件和硬件的兼容性稳定, 要求本项目的机房计算机和软件为同一品牌;",
"一) 整体要求",
"1 安装部署快捷, 升级简易方便, 全中文人性化界面设计, 配有详细的在线帮助, 支持主窗口功能按钮 、浮动工具条 、右键菜单 、快捷键多项操作方式。",
"▲2 采用核心的动态局部截屏及实时压缩技术, 在网络条件较差时亦能体现良好的性能; 可根据网络条件调节网络补偿强度, 根据广播内容调节广播及录制效率, 使广播达到最佳效果。 防杀进程 、断线保护 、卸载密码保护等辅助功能维护教学秩序。 文件分发和提交支持拖拽添加,教师或学生一次分发或提交多个文件夹或多个文件目录下的文件。 与云虚拟桌面无缝集成。",
"二) 课堂教学",
"1 教师演示: 教师可对单一 、部分或全体学生进行屏幕演示, 全屏 、窗口方式均可。",
"2 教师演示速度增强: 屏幕广播时支持多种画面质量的调节, 根据网络的不同选择最好的效果进行教学。",
"3 屏幕笔: 教师教学使用的辅助工具, 突出显示项目 、添加注释, 添加批注等等。",
"4 视频广播: 采用流媒体技术, 实现教师机播放的视频同步广播到学生机, 且达到流畅无延时, 支持几乎所有常见的媒体音视频格式, WindowsMedia 文件, VCD 文件, DVD 文件, Real 文件, AVI 文件, MP3 等主流文件格式, 支持 720p 、1080p 的高清视频。",
"视频直播:通过 USB 摄像头将教师的画面实时广播到学生机,达到更形象的教学效果,具有引导客户选择视频设备的提示画面,以便客户快速完成摄像头设备的设置。",
"语音广播:将教师机麦克风或其他输入设备(如磁带 、 CD 的声音广播给学生,教学过程中, 可以请任何一位已登录的学生发言, 其他学生和教师收听该学生发言 。",
"语音对讲: 教师可以选择任意一名已登录学生 与其进行双向语音交谈, 除教师和此学生外, 其他学生不会受到干扰, 可以动态切换对讲对象。",
"5 学生演示: 教师可选定一台学生机作为示范, 由此学生代替教师进行示范教学。(提供此功能界面截图证明)",
"6 分组教学: 教师分派组长执行指定的功能, 组长代替教师进行小组教学, 小组不需要再临时创建, 可以直接使用既有分组信息, 教师可以监控每个分组的教学过程, 以了解分组教学的进度 。(提供此功能界面截图证明)",
"7 分组讨论: 教师可以创建多个小组进行讨论活动, 并可任意选择分组加入讨论活动 。 同组师生支持多种方式进行交流, 包括文字 表情, 图片等 。(提供此功能界面截图证明)",
"8 屏幕录制: 教师机可以将本地的操作和讲解过程录制为 ASF 录像文件, 可以用 Windows 自带的 MediaPlayer 直接播放。",
"9 学生端屏幕录制 、 回放: 学生端接收教师端广播的时候可以自动录制教师机广播教学的过程, 课后可以重复观看学习。",
"10 文件分发: 允许教师将教师机不同盘符中的目录或文件一起发送至生机的某目录下 。 目录不存在自动新建此目录; 盘符不存在或路径非法不允许分发; 文件已存在选择自动覆盖或保留原始文件。",
"11 作业提交: 学生把做好的作业直接提交到教师机, 方便教师批改作业要收取的麻烦 。通过特殊设置, 学生提交作业时必需经过教师审批通过后才可提交, 教师可以选择接收和拒绝学生提交的文件 。 并且教师可以限制学生提交文件的数目和大小。",
"12 网络快照: 教师可以在监控学生的时候, 对学生画面拍快照, 保存学生画面的截图。",
"13 屏幕监视: 教师机可以监视单一 、部分 、全体学生机的屏幕, 教师机每屏可监视多个学生屏幕 。可以控制教师机监控的同屏幕各窗口间 、屏幕与屏幕间的切换速度 。可手动或自动循环监视 。(提供此功能界面截图证明)",
"14 频道教学: 支持多达 32 个频道的划分, 一个教师可对单个班级或多个班级同时上课; 多个教师可同时对多个班级进行不同内容的教学。",
"三) 教学评测",
"随堂小考: 教师启动快速的单题考试或随堂调查, 限定考试时间, 学生答题后立即给出结果, 结果显示学生答案柱状图分析和答题时间, 可作为抢答依据。",
"四) 课堂管理",
"1 签到: 提供学生名单管理工具, 为软件和考试模块提供实名验证 。提供点名功能, 支持保留学生多次登录记录 、考勤统计 、签到信息的导出与对比。",
"2 班级模型: 有单独的管理界面, 实现对班级模型的统一管理, 并能够导入 、导出, 调用不同网络教室中的班级模型。",
"上网限制: 设定学生访问网站的黑名单或白名单, 对学生可以访问的 Internet 站点进行管理 。支持多浏览器限制, 如 QQ 、IE 、谷歌 、360 、遨游等浏览器 。(提供此功能界面截图证明)",
"3 程序限制:通过各种策略的应用,可防止学生在教学过程中打游戏,或使用 QQ MSN 等聊天工具 。(提供此功能界面截图证明)",
"学生端属性查看: 教师可以获取学生端计算机的名称 、登录名和其它常用信息, 并可以列出学生端的应用程序 、进程和进程 ID 教师还可以远程终止学生端的进程。",
"4 系统日志: 显示和自动保存系统运行过程中的关键事件, 包括学生登录登出, 资源不足, 提交文件等。",
"5 黑屏肃静: 教师可以对单一 、部分 、全体学生执行黑屏肃静来禁止其进行任何操作, 达到专心听课目的, 教师可自定义黑屏的内容与图片。",
"6 远程命令: 可以进行远程开机 、关机 、重启等操作, 远程关闭所有学生正在执行的应用程序功能。",
"7 分组管理: 教师可以新建, 删除, 重命名分组, 添加和删除分组中的成员, 设置小组长 。分组信息随班级模型永久保存, 下次上课可以直接使用保存的分组。",
"8 图标监看: 班级模型中可以显示学生机桌面的缩图 。缩图显示大小也可自由设定 。(提供此功能界面截图证明)",
"9 自动锁屏: 独有的断线保护自动锁屏技术, 通过网卡的是否激活来锁定屏幕, 避免学生拔掉网线违反纪律。",
"10 防杀进程: 为安全起见, 学生端程序运行后, 防止学生通过任务管理器结束学生端程序进程来逃脱教师控制。",
"请求帮助: 学生端遇到问题可请求帮助, 教师端可远程遥控帮助学生解决问题。",
"11 远程消息: 教师与学生能够使用远程消息进行交流, 并可以允许和阻止学生发送文字消息。",
"12 远程设置: 远程设置学生桌面主题 、桌面背景 、屏幕保护方案 、学生的频道号 和音量 、学生的卸载密码, 是否启用进程保护, 断线锁屏 热键退出等。"
]
},
"办公桌椅": {
"办公桌椅": [
"1 、桌子规格: 1600*800*750 mm 采用优质高密度板, 经防虫 、防腐 、防霉等化学处理 。",
"2 、面料: 采用进口胡桃木皮( 0.6 mm )拼花饰面, 胡桃木实木封边, 颜色均匀, 纹理自然, 拼接严密。",
"3 、油漆: 采用名牌优质环保聚脂油漆,涂层平整 、光 滑 、清晰 、无颗粒 、气泡、 渣点, 颜色均匀。",
"4 、五金配件: 采用优质名牌五金配件, 开启灵活轻便, 各部位安装结 构严密、 牢 固可靠 、平稳, 无松动 、倾斜 、摇晃等现 象。",
"5 、椅子: 定制, 实木框架, 喷环保型聚脂亚光漆, 经过高温防虫处 理, 符合人 体工程学设计。"
]
},
"文件柜": {
"文件柜": [
"1 、规格: 1800mm*850mm*390mm 两层两抽, 锁具精美安全系数高。",
"2 、 国际亚光白色, 采用优质冷轧钢板经剪切, 冲压, 折弯, 焊接, 装配而成, 板材厚度≥0.5mm。",
"3 、焊接部分采用高标准熔接焊, 表面平整光滑。",
"4 、柜面: 柜面采用绿色环保型粉末静电喷塑, 对人体及周围环境不产生危害, 无毒 、无副作用, 使用时无异味。",
"5 、格板: 文件柜格板高度可调, 坚固耐用, 性能优良, 可存放大量文件资料。"
]
},
"体育运动器材": {
"移动式标准篮球架12座": [
"1 、标准篮板: 12MM 高强度防爆玻璃钢, 国际标准。",
"2 、篮球架的主立柱: 15cm*15cm。",
"3 、篮球架的主杆与篮板之间的拉杆: 10*16CM 壁厚 2.5mm 弯梁。",
"4、篮球架的高度篮架伸臂为 2.25m,篮圈到地面标准高度为 3.05 米(左右)。",
"5 、配重箱体为加厚铸铁底座 2m*1m 单支配重不低于 550kg 伸臂不小于 1.8m。",
"6、篮框新国际标准带弹簧 篮圈采用 20MM 实心圆钢,链接底钢板 5MM链接侧钢板 4MM终身保修。",
"7 、方管拉杆 38 管, 钢铁部件 3 年免费维修, 使用年限不低于 8 年。",
"8、所有钢制件表面均经酸洗、磷化等初级处理后在喷涂线上采用静电环氧基粉末喷涂完成最后表面处理 涂层厚度 70—80um 铅笔硬度达 3H+ 产品经 GB 1771-91 36 小时盐雾试验涂膜无变化划格处单面腐蚀2mm产品具有 耐酸碱 、耐湿热 、抗老化 、外观美观等优点, 能适合潮湿和酸 雨环境, 且产品 涂料配方不含有毒元素, 避免损害使用者的健康。",
"9 、施工前要实地考察, 此为旧场地改造, 共计 12 个, 包安装。"
]
},
}
data1={
"文件柜": {
"交换机": [
"1 、规格: 1800mm*850mm*390mm 两层两抽, 锁具精美安全系数高。",
"2 、 国际亚光白色, 采用优质冷轧钢板经剪切, 冲压, 折弯, 焊接, 装配而成, 板材厚度≥0.5mm。",
"3 、焊接部分采用高标准熔接焊, 表面平整光滑。",
"4 、柜面: 柜面采用绿色环保型粉末静电喷塑, 对人体及周围环境不产生危害, 无毒 、无副作用, 使用时无异味。",
"5 、格板: 文件柜格板高度可调, 坚固耐用, 性能优良, 可存放大量文件资料。"
],
"文件柜-2": [
"1 、规格: 1800mm*850mm*390mm 两层www两抽 锁具精美安全系数高。",
"2 、 国际亚光白色, 采用优质冷轧钢板经剪切, 冲压, 折弯, 焊接, 装配而成, 板材厚度≥0.5mm。",
"3 、焊接部分采用高标准熔接焊, 表面平整光滑。",
"4 、柜面: 柜面采用绿色环保型粉末静电喷塑, 对人体及周围环境不产生危害, 无毒 、无副作用, 使用时无异味。",
"5 、格板: 文件柜格板高度可调, 坚固耐用, 性能优良, 可存放大量文件资料。"
]
},
"文件柜11": {
"交换机": [
"1 、规格: 1800mm*850mm*390mm 两层两抽, 锁具精美安全系数高。",
"2 、 国际亚光白色, 采用优质冷轧钢板经剪切, 冲压, 折弯, 焊接, 装配而成, 板材厚度≥0.5mm。",
"3 、焊接部分采用高标准熔接焊, 表面平整光滑。",
"4 、柜面: 柜面采用绿色环保型粉末静电喷塑, 对人体及周围环境不产生危害, 无毒 、无副作用, 使用时无异味。",
"5 、格板: 文件柜格板高度可调, 坚固耐用, 性能优良, 可存放大量文件资料。"
]
}
}
good_list=["交换机",
"户内全彩LED屏全彩高刷",
"发送盒",
"LED显示屏控制系统",
"视频处理器",
"智能配电柜",
"台式电脑",
"控制桌(定制)",
"结构边框",
"线材(按需)",
"包装材料",
"专业功放",
"天线分配器",
"主扩全频专业音箱",
"辅助专业音箱",
"壁挂支架",
"返听专业音箱",
"返听专业功放",
"超低频专业音箱",
"音箱地插",
"调音台",
"音频处理器",
"抑制器",
"无线话筒",
"话筒呼叫控制嵌入软件",
"话筒天线",
"有源监听音箱",
"电源时序器",
"音频连接线",
"机柜",
"其它辅材(音箱线、电源线、网线、视频线等)",
"会议座椅",
"电动窗帘系统",
"备课一体机电脑",
"云平台管理软件",
"教学互动应用软件",
"办公桌椅",
"文件柜",
"移动式标准篮球架12座"
]
def extract_matching_keys(data, good_list, special_keys=None, parent_key=''):
def get_suffix(n):
"""
根据数字n返回对应的字母后缀
1 -> 'a', 2 -> 'b', ..., 26 -> 'z', 27 -> 'aa', 28 -> 'ab', ...
"""
suffix = ''
while n > 0:
n, r = divmod(n - 1, 26)
suffix = chr(97 + r) + suffix
return suffix
def count_matching_keys(data, patterns, special_keys, counter=None):
"""递归统计匹配键的出现次数,仅统计值为列表的键"""
if counter is None:
counter = defaultdict(int)
if isinstance(data, dict):
for key, value in data.items():
if isinstance(value, list):
if key not in special_keys and any(pattern.match(key) for pattern in patterns):
counter[key] += 1
elif isinstance(value, dict):
count_matching_keys(value, patterns, special_keys, counter)
elif isinstance(data, list):
for item in data:
if isinstance(item, (dict, list)):
count_matching_keys(item, patterns, special_keys, counter)
return counter
def process_data(data, patterns, special_keys, key_counter, suffix_map, filtered_data, parent_key):
"""递归处理数据并构建结果"""
def get_suffix_label(key):
suffix_map[key] += 1
return get_suffix(suffix_map[key])
if isinstance(data, dict):
for key, value in data.items():
if isinstance(value, list):
# 处理值为列表的键
if any(pattern.match(key) for pattern in patterns):
new_key = generate_key(key, parent_key, key_counter, suffix_map, special_keys)
filtered_data[new_key] = value
elif isinstance(value, dict):
# 继续递归处理嵌套字典
new_parent_key = key if parent_key == '' else f"{parent_key}{key}"
process_data(value, patterns, special_keys, key_counter, suffix_map,
filtered_data, new_parent_key)
elif isinstance(data, list):
for item in data:
if isinstance(item, (dict, list)):
process_data(item, patterns, special_keys, key_counter, suffix_map,
filtered_data, parent_key)
def generate_key(key, parent_key, key_counter, suffix_map, special_keys):
"""生成新的键名"""
if key in special_keys and parent_key:
return f"{parent_key}{key}"
elif key_counter[key] > 1:
suffix = get_suffix(suffix_map[key] + 1)
suffix_map[key] += 1
return f"{key}-{suffix}"
return key
if special_keys is None:
special_keys = []
patterns = [re.compile(r'^' + re.escape(g) + r'(?:-\d+)?$') for g in good_list]
# 先统计所有匹配键的出现次数,仅统计值为列表的键
key_counter = count_matching_keys(data, patterns, special_keys)
# 初始化后缀映射
suffix_map = {key: 0 for key, count in key_counter.items() if count > 1}
# 用于存储最终结果
filtered_data = {}
# 递归处理数据
process_data(data, patterns, special_keys, key_counter, suffix_map, filtered_data, parent_key)
return filtered_data
tech_deviation = extract_matching_keys(data, good_list)
print(json.dumps(tech_deviation,ensure_ascii=False,indent=4))

View File

@ -3,7 +3,7 @@ import json
import re
from PyPDF2 import PdfReader
from flask_app.general.doubao import read_txt_to_string
from flask_app.general.doubao import read_txt_to_string, pdf2txt
from flask_app.general.json_utils import combine_json_results,clean_json_string
from flask_app.general.通义千问long import upload_file,qianwen_long_stream
from flask_app.货物标.截取pdf货物标版 import extract_common_header, clean_page_content
@ -246,11 +246,14 @@ def merge_requirements(input_dict):
final_dict[key] = final_dict[key].strip()
return final_dict
#,"总\s*体\s*要\s*求","进\s*度\s*要\s*求","培\s*训\s*要\s*求"
def get_business_requirements(procurement_path,processed_filepath):
file_id=upload_file(procurement_path)
required_keys = ["\s*术\s*要\s*求","\s*务\s*要\s*求", "\s*务\s*要\s*求", "\s*他\s*要\s*求","\s*体\s*要\s*求","\s*度\s*要\s*求","\s*训\s*要\s*求"]
required_keys = ["\s*术\s*要\s*求","\s*务\s*要\s*求", "\s*务\s*要\s*求", "\s*他\s*要\s*求"]
contained_keys=find_exists(procurement_path,required_keys)
print(contained_keys)
if not contained_keys:
return {}
# queries = generate_queries(truncate_file, contained_keys)
user_query=generate_user_query_template(contained_keys,processed_filepath)
# print(user_query)
@ -264,8 +267,9 @@ def get_business_requirements(procurement_path,processed_filepath):
#TODO:改为先判断,再摘取
if __name__ == "__main__":
# truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\e4be098d-b378-4126-9c32-a742b237b3b1\\ztbfile_procurement.docx"
truncate_file=r"C:\Users\Administrator\Desktop\fsdownload\5901b181-b55f-4107-9f30-c85d607b1fa0\ztbfile_procurement.pdf"
processed_filepath=""
truncate_file=r"C:\Users\Administrator\Desktop\fsdownload\fa0d51a1-0d63-4c0d-9002-cf8ac3f2211a\ztbfile_procurement.pdf"
# file_id = upload_file(truncate_file)
res=get_business_requirements(truncate_file,"")
processed_filepath = pdf2txt(truncate_file)
res=get_business_requirements(truncate_file,processed_filepath)
print(json.dumps(res, ensure_ascii=False, indent=4))

View File

@ -13,7 +13,6 @@ def get_global_logger(unique_id):
return logging.getLogger() # 获取默认的日志器
logger = logging.getLogger(unique_id)
return logger
logger = None
# fitz库版本
# def extract_common_header(pdf_path):
@ -736,9 +735,7 @@ def process_input(input_path, output_folder, selection, output_suffix):
return ['']
def truncate_pdf_multiple(pdf_path, output_folder,unique_id="123"):
global logger
logger = get_global_logger(unique_id)
def truncate_pdf_multiple(pdf_path, output_folder,logger):
base_file_name = os.path.splitext(os.path.basename(pdf_path))[0]
truncate_files = []
@ -769,11 +766,12 @@ def truncate_pdf_multiple(pdf_path, output_folder,unique_id="123"):
if merged_path:
# 合并成功,添加合并后的文件路径
truncate_files.append(merged_path)
logger.info(f"已生成合并文件: {merged_output_path}")
# logger.info(f"已生成合并文件: {merged_output_path}")
else:
# 合并失败,添加空字符串
truncate_files.append("")
logger.warning(f"合并失败,没有生成合并文件 for {pdf_path}")
logger.info("已截取文件路径"+str(truncate_files))
return truncate_files
#小解析,只需要前三章内容
@ -789,7 +787,6 @@ def truncate_pdf_specific_goods(pdf_path, output_folder, selections,unique_id="1
Returns:
list: 截取的文件路径列表包括合并后的文件路径如果有
"""
global logger
logger = get_global_logger(unique_id)
base_file_name = os.path.splitext(os.path.basename(pdf_path))[0]
truncate_files = []
@ -838,7 +835,7 @@ if __name__ == "__main__":
# input_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\a091d107-805d-4e28-b8b2-0c7327737238\\ztbfile.pdf"
# output_folder = "C:\\Users\\Administrator\\Desktop\\fsdownload\\a091d107-805d-4e28-b8b2-0c7327737238\\tmp"
output_folder=r"C:\Users\Administrator\Desktop\new招标文件\output5"
# files = truncate_pdf_multiple(input_path, output_folder)
files = truncate_pdf_multiple(input_path, output_folder)
# selections = [3,5]
# files=truncate_pdf_specific_goods(input_path,output_folder,selections)
# print(files)

View File

@ -566,7 +566,7 @@ def test_all_files_in_folder(input_folder, output_folder):
if __name__ == "__main__":
start_time=time.time()
# truncate_file="C:\\Users\\Administrator\\Desktop\\fsdownload\\469d2aee-9024-4993-896e-2ac7322d41b7\\ztbfile_procurement.docx"
truncate_file=r"C:\Users\Administrator\Desktop\货物标\output1\包头市公安支队机动车查验监管系统招标文201907_procurement.pdf"
truncate_file=r"D:\flask_project\flask_app\static\output\output1\a91d59a5-d04a-4588-98e4-ddc6e9caf999\ztbfile_procurement.pdf"
# invalid_path="D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89\\ztbfile.pdf"
# truncate_file="D:\\flask_project\\flask_app\\static\\output\\output1\\e7dda5cb-10ba-47a8-b989-d2993d34bb89\\ztbfile_procurement.docx"
# output_folder="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\tmp"

View File

@ -59,12 +59,13 @@ def fetch_procurement_reqs(procurement_path, invalid_path):
#TODO:技术要求可以在技术参数之后执行,把完整的技术参数输入,问大模型,除了上述内容还有哪些,这样的话把技术标和其他的区分开。
#TODO: 094有问题
if __name__ == "__main__":
start_time=time.time()
output_folder = "C:\\Users\\Administrator\\Desktop\\货物标\\货物标output"
# file_path="C:\\Users\\Administrator\\Desktop\\货物标\\output1\\2-招标文件2020年广水市中小学教师办公电脑系统及多媒体“班班通”设备采购安装项目_procurement.pdf"
procurement_path = r"C:\Users\Administrator\Desktop\fsdownload\5901b181-b55f-4107-9f30-c85d607b1fa0\ztbfile_procurement.pdf"
procurement_docpath=r"C:\Users\Administrator\Desktop\fsdownload\5901b181-b55f-4107-9f30-c85d607b1fa0"
procurement_path = r"C:\Users\Administrator\Desktop\fsdownload\fa0d51a1-0d63-4c0d-9002-cf8ac3f2211a\ztbfile_procurement.pdf"
procurement_docpath=r"C:\Users\Administrator\Desktop\fsdownload\fa0d51a1-0d63-4c0d-9002-cf8ac3f2211a"
invalid_path="C:\\Users\\Administrator\\Desktop\\fsdownload\\db79e9e0-830e-442c-8cb6-1d036215f8ff\\ztbfile.pdf"
res=fetch_procurement_reqs(procurement_path,invalid_path)
print(json.dumps(res, ensure_ascii=False, indent=4))

View File

@ -47,8 +47,7 @@ def preprocess_files(output_folder, file_path, file_type,logger):
# # 异步上传知识库
# future_knowledge = executor.submit(addfileToKnowledge, docx_path, "招标解析" + unique_id)
# 调用截取PDF多次
truncate_files = truncate_pdf_multiple(pdf_path,
output_folder) # index: 0->商务技术服务要求 1->评标办法 2->资格审查 3->投标人须知前附表 4->投标人须知正文
truncate_files = truncate_pdf_multiple(pdf_path, output_folder,logger) # index: 0->商务技术服务要求 1->评标办法 2->资格审查 3->投标人须知前附表 4->投标人须知正文
# 处理各个部分
invalid_path=pdf_path
@ -78,28 +77,39 @@ def preprocess_files(output_folder, file_path, file_type,logger):
'merged_baseinfo_path': merged_baseinfo_path
}
def fetch_project_basic_info(invalid_path,merged_baseinfo_path, procurement_path, clause_path,logger):
def fetch_project_basic_info(invalid_path, merged_baseinfo_path, procurement_path, clause_path, logger):
logger.info("starting 基础信息...")
start_time = time.time()
try:
if not merged_baseinfo_path:
merged_baseinfo_path = invalid_path
if not procurement_path:
procurement_path=invalid_path
basic_res = combine_basic_info(merged_baseinfo_path, procurement_path,clause_path,invalid_path)
base_info, good_list = post_process_baseinfo(basic_res,logger)
procurement_path = invalid_path
basic_res = combine_basic_info(merged_baseinfo_path, procurement_path, clause_path, invalid_path)
base_info, good_list = post_process_baseinfo(basic_res, logger)
result = base_info, good_list
except Exception as exc:
logger.error(f"Error in 基础信息: {exc}")
# 返回默认值
result = {"基础信息": {}}, []
end_time = time.time()
logger.info(f"基础信息 done耗时{end_time - start_time:.2f}")
return base_info, good_list
return result
def fetch_qualification_review(invalid_path,qualification_path, notice_path,logger):
def fetch_qualification_review(invalid_path, qualification_path, notice_path, logger):
logger.info("starting 资格审查...")
start_time = time.time()
review_standards_res = combine_qualification_review(invalid_path,qualification_path, notice_path)
try:
review_standards_res = combine_qualification_review(invalid_path, qualification_path, notice_path)
result = review_standards_res
except Exception as exc:
logger.error(f"Error in 资格审查: {exc}")
# 返回默认值
result = {"资格审查": {}}
end_time = time.time()
logger.info(f"资格审查 done耗时{end_time - start_time:.2f}")
return review_standards_res
return result
def fetch_evaluation_standards(invalid_path, evaluation_method_path,logger):
logger.info("starting 商务评分和技术评分...")
@ -116,37 +126,55 @@ def fetch_evaluation_standards(invalid_path, evaluation_method_path,logger):
"commercial_standards": commercial_standards
}
def fetch_invalid_requirements(invalid_docpath, output_folder,logger):
def fetch_invalid_requirements(invalid_docpath, output_folder, logger):
logger.info("starting 无效标与废标...")
start_time = time.time()
try:
find_invalid_res = combine_find_invalid(invalid_docpath, output_folder)
result = find_invalid_res
except Exception as exc:
logger.error(f"Error in 无效标与废标: {exc}")
# 返回默认值
result = {"无效标与废标": {}}
end_time = time.time()
logger.info(f"无效标与废标 done耗时{end_time - start_time:.2f}")
return find_invalid_res
return result
def fetch_bidding_documents_requirements(invalid_path,merged_baseinfo_path,clause_path,logger):
def fetch_bidding_documents_requirements(invalid_path, merged_baseinfo_path, clause_path, logger):
logger.info("starting 投标文件要求...")
if not merged_baseinfo_path:
merged_baseinfo_path=invalid_path
merged_baseinfo_path = invalid_path
start_time = time.time()
selection=1
fetch_bidding_documents_requirements_json = extract_from_notice(merged_baseinfo_path,clause_path, selection)
selection = 1
try:
fetch_bidding_documents_requirements_json = extract_from_notice(merged_baseinfo_path, clause_path, selection)
result = {"投标文件要求": fetch_bidding_documents_requirements_json}
except Exception as exc:
logger.error(f"Error in 投标文件要求: {exc}")
# 返回默认值,假设默认值为一个空字典
result = {"投标文件要求": {}}
end_time = time.time()
logger.info(f"投标文件要求 done耗时{end_time - start_time:.2f}")
return {"投标文件要求": fetch_bidding_documents_requirements_json}
return result
# 开评定标流程
def fetch_bid_opening(invalid_path,merged_baseinfo_path,clause_path,logger):
def fetch_bid_opening(invalid_path, merged_baseinfo_path, clause_path, logger):
logger.info("starting 开评定标流程...")
if not merged_baseinfo_path:
merged_baseinfo_path=invalid_path
merged_baseinfo_path = invalid_path
start_time = time.time()
selection=2
fetch_bid_opening_json = extract_from_notice(merged_baseinfo_path,clause_path, selection)
selection = 2
try:
fetch_bid_opening_json = extract_from_notice(merged_baseinfo_path, clause_path, selection)
result = {"开评定标流程": fetch_bid_opening_json}
except Exception as exc:
logger.error(f"Error in 开评定标流程: {exc}")
# 返回默认值,假设默认值为一个空字典
result = {"开评定标流程": {}}
end_time = time.time()
logger.info(f"开评定标流程 done耗时{end_time - start_time:.2f}")
return {"开评定标流程": fetch_bid_opening_json}
return result
def post_process_baseinfo(base_info,logger):
@ -230,7 +258,14 @@ def goods_bid_main(output_folder, file_path, file_type, unique_id):
yield json.dumps({key: transform_json_values(result)}, ensure_ascii=False)
except Exception as exc:
logger.error(f"Error processing {key}: {exc}")
yield json.dumps({'error': f'Error processing {key}: {str(exc)}'}, ensure_ascii=False)
if key == 'evaluation_standards':
# 返回默认的商务评分和技术评分
default_evaluation = {
'technical_standards': {"技术评分": ""},
'commercial_standards': {"商务评分": ""}
}
yield json.dumps(default_evaluation, ensure_ascii=False)
# yield json.dumps({'error': f'Error processing {key}: {str(exc)}'}, ensure_ascii=False)
if collected_good_list is not None:
yield json.dumps({'good_list': transform_json_values(collected_good_list)}, ensure_ascii=False)

View File

@ -15,5 +15,3 @@ PyMuPDF==1.24.1
openai==1.33.0
pathlib==1.0.1
alibabacloud_bailian20231229==1.7.0
celery==5.2.3
redis==4.1.0