From 0388beaeaa6e25cc46f921e6c08be3db67537732 Mon Sep 17 00:00:00 2001 From: zy123 <646228430@qq.com> Date: Wed, 12 Feb 2025 14:55:35 +0800 Subject: [PATCH] =?UTF-8?q?2.12=20=E4=BD=BF=E7=94=A8turbo=E4=BD=9C?= =?UTF-8?q?=E4=B8=BAplus=E8=B6=85=E9=99=90=E6=97=B6=E7=9A=84=E4=BF=9D?= =?UTF-8?q?=E5=BA=95=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 72 +- docker-compose.yml | 9 +- flask_app/general/llm/doubao.py | 110 +- flask_app/general/llm/model_continue_query.py | 3 +- flask_app/general/llm/qianwen_plus.py | 153 ++ flask_app/general/llm/qianwen_turbo.py | 1450 +++++++++++++++++ flask_app/general/llm/多线程提问.py | 31 +- flask_app/general/llm/大模型通用函数.py | 151 ++ .../{通义千问long_plus.py => 通义千问long.py} | 155 +- flask_app/general/商务技术评分提取.py | 17 +- .../general/投标人须知正文提取指定内容.py | 2 +- flask_app/general/无效标和废标公共代码.py | 4 +- flask_app/general/通用功能函数.py | 11 +- .../old_version/不得存在及禁止投标情形_old.py | 2 +- flask_app/old_version/判断是否分包等_old.py | 2 +- .../商务评分技术评分整合old_version.py | 2 +- flask_app/old_version/基础信息整合_old.py | 2 +- .../old_version/无效标和废标公共代码_old.py | 4 +- .../无效标和废标和禁止投标整合_old.py | 2 +- flask_app/old_version/评分标准提取main_old.py | 2 +- flask_app/old_version/资格审查模块old_old.py | 2 +- flask_app/old_version/资格评审old_old.py | 2 +- flask_app/routes/utils.py | 2 +- flask_app/routes/偏离表数据解析main.py | 2 +- flask_app/routes/判断是否是招标文件.py | 2 +- flask_app/routes/小解析main.py | 2 +- flask_app/test_case/test_doubao.py | 3 +- flask_app/test_case/test_qianwen_long.py | 2 +- flask_app/test_case/test_轮询.py | 35 + flask_app/工程标/基础信息整合工程标.py | 2 +- flask_app/工程标/形式响应评审.py | 2 +- flask_app/工程标/截取pdf工程标版.py | 6 +- flask_app/工程标/资格审查模块main.py | 2 +- flask_app/工程标/资格评审.py | 2 +- flask_app/货物标/商务服务其他要求提取.py | 5 +- flask_app/货物标/基础信息解析货物标版.py | 13 +- flask_app/货物标/截取pdf货物标版.py | 6 +- flask_app/货物标/技术参数要求提取.py | 5 +- flask_app/货物标/资格审查main.py | 2 +- 39 files changed, 1929 insertions(+), 352 deletions(-) create mode 100644 flask_app/general/llm/qianwen_plus.py create mode 100644 flask_app/general/llm/qianwen_turbo.py create mode 100644 flask_app/general/llm/大模型通用函数.py rename flask_app/general/llm/{通义千问long_plus.py => 通义千问long.py} (65%) create mode 100644 flask_app/test_case/test_轮询.py diff --git a/README.md b/README.md index 91d48c2..f8df200 100644 --- a/README.md +++ b/README.md @@ -84,36 +84,70 @@ bid-assistance/test 里面找个文件的url,推荐'094定稿-湖北工业大 ### 项目中做限制的地方 -**大模型的限制** +#### **账号、服务器分流** + +服务器分流:目前linux服务器和windows服务器主要是硬件上的分流(文件切分需要消耗CPU资源),大模型基底还是调用阿里,共用的tpm qpm。 + +账号分流:qianwen_plus下的 + +``` +api_keys = cycle([ + os.getenv("DASHSCOPE_API_KEY"), + # os.getenv("DASHSCOPE_API_KEY_BACKUP1"), + # os.getenv("DASHSCOPE_API_KEY_BACKUP2") +]) +api_keys_lock = threading.Lock() +def get_next_api_key(): + with api_keys_lock: + return next(api_keys) + +api_key = get_next_api_key() +``` + +只需轮流使用不同的api_key即可。目前没有启用。 + + + +#### **大模型的限制** general/llm下的doubao.py 和通义千问long_plus.py **目前是linux和windows各部署一套,因此项目中的qps是对半的,即calls=?** -1. 这是qianwen-long的限制(针对阿里qpm为1200,投标生成和解析对半分600,每秒就是10,又linux和windows服务器对半,就是5;) +1. 这是qianwen-long的限制(针对阿里qpm为1200,每秒就是20,又linux和windows服务器对半,就是10;TPM无上限) ``` @sleep_and_retry -@limits(calls=5, period=1) # 每秒最多调用4次 +@limits(calls=10, period=1) # 每秒最多调用10次 def rate_limiter(): pass # 这个函数本身不执行任何操作,只用于限流 ``` -2. 这是qianwen-plus的限制(针对tpm为1000万,每个请求2万tokens,那么linux和windows总的qps为8时,8x60x2=960<1000。) +2. 这是qianwen-plus的限制(针对tpm为1000万,每个请求2万tokens,那么linux和windows总的qps为8时,8x60x2=960<1000。单个为4) + **经过2.11号测试,calls=4时最高TPM为800,因此把目前稳定版把calls设为5** + + **2.12,用turbo作为超限后的承载,目前把calls设为7** ``` @sleep_and_retry -@limits(calls=4, period=1) # 每秒最多调用4次 +@limits(calls=7, period=1) # 每秒最多调用7次 def qianwen_plus(user_query, need_extra=False): logger = logging.getLogger('model_log') # 通过日志名字获取记录器 ``` +3. qianwen_turbo的限制(TPM为500万,由于它是plus后的手段,稳妥一点,qps设为6,两个服务器分流即calls=3) + +``` +@sleep_and_retry +@limits(calls=3, period=1) # 500万tpm,每秒最多调用6次,两个服务器分流就是3次 (plus超限后的保底手段,稳妥一点) +``` + **重点!!**后续阿里扩容之后成倍修改这块**calls=?** 如果不用linux和windows负载均衡,这里的calls也要乘2!! -**接口的限制** +#### **接口的限制** 1. start_up.py的def create_app()函数,限制了对每个接口同时100次请求。这里事实上不再限制了(因为100已经足够大了),默认限制做到大模型限制这块。 @@ -132,12 +166,9 @@ app.connection_limiters['upload'] = ConnectionLimiter(max_connections=100) def zbparse(): ``` - 这里限制了每个接口内部执行的时间,暂时设置到了30分钟!(不包括排队时间)超时就是解析失败 - - -**后端的限制:** +#### **后端的限制:** 目前后端发起招标请求,如果发送超过100(max_connections=100)个请求,我这边会排队后面的请求,这时后端的计时器会将这些请求也视作正在解析中,事实上它们还在排队等待中,这样会导致在极端情况下,新进的解析文件速度大于解析的速度,排队越来越长,后面的文件会因为等待时间过长而直接失败,而不是'解析失败'。 @@ -354,4 +385,23 @@ start_up.py是启动脚本,run_serve也是启动脚本,是对start_up.py的 ![1](md_files/17.png) -这个是解析得来的结果,适合给前端展示,但是要生成商务技术评议偏离表的话,需要再调一次大模型,对该数据进行重新归纳,以字符串列表为佳。再传给后端。(未做) \ No newline at end of file +这个是解析得来的结果,适合给前端展示,但是要生成商务技术评议偏离表的话,需要再调一次大模型,对该数据进行重新归纳,以字符串列表为佳。再传给后端。(未做) + + + +### 如何定位问题 + +1. 查看static下的output文件夹 (upload大解析对应output1) +2. docker-compose文件中规定了数据卷挂载的路径:- /home/Z/zbparse_output_dev:/flask_project/flask_app/static/output + 也就是说static/output映射到了服务器的Z/zbparse_output_dev文件夹 +3. 根据时间查找哪个子文件夹(uuid作为子文件名) +4. 查看是否有final_result.json文件,如果有,说明解析流程正常结束了,问题可能出在后端(a.后端接口请求超限30分钟 b.后处理存在解析数据的时候出错) + +​ 也可能出现在自身解析,可以查看子文件内的log.txt,查看日志。 + +5. 若解析正常(有final_result)但解析不准,可以根据以下定位: + +​ a.查看子文件夹下的文件切分是否准确,例如:如果评标办法不准确,那么查看ztbfile_evaluation_methon,是否正确切到了评分细则。如果切到了,那就改general/商务技术评分提取里的提示词;否则修改截取pdf那块关于'评标办法'的正则表达式。 + +​ b.总之是**先看切的准不准,再看提示词能否优化**,都要定位到对应的代码中! + diff --git a/docker-compose.yml b/docker-compose.yml index 84e606e..92cb7ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,8 @@ services: cpus: 4.0 # 限制容器使用2个CPU核心 security_opt: - seccomp:unconfined -# 可选:定义网络或其他全局配置 -# networks: -# default: -# driver: bridge + +# 如果单独服务器的话,注释以下,不做限制: +# mem_limit: "12g" # 容器最大可使用内存为8GB +# mem_reservation: "4g" # 容器保证可使用内存为4GB +# cpus: 4.0 # 限制容器使用2个CPU核心 \ No newline at end of file diff --git a/flask_app/general/llm/doubao.py b/flask_app/general/llm/doubao.py index 5ddccd7..491de0c 100644 --- a/flask_app/general/llm/doubao.py +++ b/flask_app/general/llm/doubao.py @@ -1,99 +1,10 @@ import os import time -import PyPDF2 import requests from ratelimit import sleep_and_retry, limits -from flask_app.general.读取文件.clean_pdf import extract_common_header, clean_page_content - -def pdf2txt(file_path): - common_header = extract_common_header(file_path) - # print(f"公共抬头:{common_header}") - # print("--------------------正文开始-------------------") - result = "" - with open(file_path, 'rb') as file: - reader = PyPDF2.PdfReader(file) - num_pages = len(reader.pages) - # print(f"Total pages: {num_pages}") - for page_num in range(num_pages): - page = reader.pages[page_num] - text = page.extract_text() - if text: - # print(f"--------第{page_num}页-----------") - cleaned_text = clean_page_content(text,common_header) - # print(cleaned_text) - result += cleaned_text - # print(f"Page {page_num + 1} Content:\n{cleaned_text}") - else: - print(f"Page {page_num + 1} is empty or text could not be extracted.") - directory = os.path.dirname(os.path.abspath(file_path)) - output_path = os.path.join(directory, 'extract.txt') - # 将结果保存到 extract.txt 文件中 - try: - with open(output_path, 'w', encoding='utf-8') as output_file: - output_file.write(result) - print(f"提取内容已保存到: {output_path}") - except IOError as e: - print(f"写入文件时发生错误: {e}") - # 返回保存的文件路径 - return output_path - -def read_txt_to_string(file_path): - """ - 读取txt文件内容并返回一个包含所有内容的字符串,保持原有格式。 - - 参数: - - file_path (str): txt文件的路径 - - 返回: - - str: 包含文件内容的字符串 - """ - try: - with open(file_path, 'r', encoding='utf-8') as file: # 确保使用适当的编码 - content = file.read() # 使用 read() 保持文件格式 - return content - except FileNotFoundError: - return "错误:文件未找到。" - except Exception as e: - return f"错误:读取文件时发生错误。详细信息:{e}" - -def get_total_tokens(text): - """ - 调用 API 计算给定文本的总 Token 数量。 注:doubao的计算方法!与qianwen不一样 - 返回: - - int: 文本的 total_tokens 数量。 - """ - # API 请求 URL - url = "https://ark.cn-beijing.volces.com/api/v3/tokenization" - - # 获取 API 密钥 - doubao_api_key = os.getenv("DOUBAO_API_KEY") - if not doubao_api_key: - raise ValueError("DOUBAO_API_KEY 环境变量未设置") - - # 请求头 - headers = { - "Content-Type": "application/json", - "Authorization": "Bearer " + doubao_api_key - } - model = "ep-20241119121710-425g6" - # 请求体 - payload = { - "model": model, - "text": [text] # API 文档中要求 text 是一个列表 - } - - try: - response = requests.post(url, headers=headers, json=payload) - response.raise_for_status() - response_data = response.json() - total_tokens=response_data["data"][0]["total_tokens"] - return total_tokens - except Exception as e: - print(f"获取 Token 数量失败:{e}") - return 0 - +from flask_app.general.llm.大模型通用函数 import get_total_tokens @sleep_and_retry -@limits(calls=10, period=1) # 每秒最多调用10次 +@limits(calls=2, period=1) # tpm=300万,每秒最多调用4次,目前两个服务器分流就是2次 def doubao_model(full_user_query, need_extra=False): """ 对于429错误,一共尝试三次,前两次等待若干时间再发起调用,第三次换模型 @@ -172,6 +83,7 @@ def doubao_model(full_user_query, need_extra=False): # 如果是 429 错误 if status_code == 429: if attempt < max_retries_429: + wait_time=1 if attempt == 0: wait_time = 3 elif attempt == 1: @@ -206,22 +118,6 @@ def doubao_model(full_user_query, need_extra=False): else: return None -def generate_full_user_query(file_path, prompt_template): - """ - 根据文件路径和提示词模板生成完整的user_query。 - - 参数: - - file_path (str): 需要解析的文件路径。 - - prompt_template (str): 包含{full_text}占位符的提示词模板。 - - 返回: - - str: 完整的user_query。 - """ - # 假设extract_text_by_page已经定义,用于提取文件内容 - full_text=read_txt_to_string(file_path) - # 格式化提示词,将提取的文件内容插入到模板中 - user_query = prompt_template.format(full_text=full_text) - return user_query if __name__ == "__main__": txt_path = r"output.txt" diff --git a/flask_app/general/llm/model_continue_query.py b/flask_app/general/llm/model_continue_query.py index 4a17dd7..aa37018 100644 --- a/flask_app/general/llm/model_continue_query.py +++ b/flask_app/general/llm/model_continue_query.py @@ -2,7 +2,8 @@ import concurrent.futures import json from flask_app.general.json_utils import clean_json_string -from flask_app.general.llm.通义千问long_plus import qianwen_long, qianwen_long_stream, qianwen_plus +from flask_app.general.llm.通义千问long import qianwen_long, qianwen_long_stream +from flask_app.general.llm.qianwen_plus import qianwen_plus def generate_continue_query(original_query, original_answer): """ diff --git a/flask_app/general/llm/qianwen_plus.py b/flask_app/general/llm/qianwen_plus.py new file mode 100644 index 0000000..864e9e8 --- /dev/null +++ b/flask_app/general/llm/qianwen_plus.py @@ -0,0 +1,153 @@ +import json +import logging +import os +import threading +import time +from itertools import cycle + +from openai import OpenAI +from ratelimit import sleep_and_retry, limits +from flask_app.general.llm.qianwen_turbo import qianwen_turbo +from flask_app.general.llm.大模型通用函数 import extract_error_details, get_total_tokens + +#若多账号实现分流,那么就在这里添加不同的API_KEY,这里要求每个模型的TPM都是一样的!!具体API_KEY写在.env文件中 +api_keys = cycle([ + os.getenv("DASHSCOPE_API_KEY"), + # os.getenv("DASHSCOPE_API_KEY_BACKUP1"), + # os.getenv("DASHSCOPE_API_KEY_BACKUP2") +]) +api_keys_lock = threading.Lock() +def get_next_api_key(): + with api_keys_lock: + return next(api_keys) +@sleep_and_retry +@limits(calls=7, period=1) # tpm是1000万,稳定下每秒最多调用10次,两个服务器分流就是5次 2.12日:增加了turbo作为承载超限的部分,可以适当扩大到calls=7 +def qianwen_plus(user_query, need_extra=False): + logger = logging.getLogger('model_log') # 通过日志名字获取记录器 + # print("call qianwen-plus...") + """ + 使用之前上传的文件,根据用户查询生成响应,并实时显示流式输出。 + 目前命中缓存局限:1.不足 256 Token 的内容不会被缓存。 + 2.上下文缓存的命中概率并不是100%,即使是上下文完全一致的请求,也存在无法命中的概率,命中概率依据系统判断而定。 + 3.若多线程同时请求,缓存无法及时更新! + 参数: + - user_query: 用户查询 + - need_extra: 是否需要返回额外数据(默认 False) + 返回: + - 当 need_extra=False 时: 返回响应内容 (str) + - 当 need_extra=True 时: 返回 (响应内容, token_usage) + """ + + # 内部定义重试参数 + max_retries = 2 + backoff_factor = 2.0 + api_key = get_next_api_key() + client = OpenAI( + api_key=api_key, + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" + ) + + for attempt in range(1, max_retries + 2): # +1 是为了包括初始调用 + try: + completion_tokens = 0 # 初始化 completion_tokens 为 0 + # 生成基于用户查询的响应 + completion = client.chat.completions.create( + model="qwen-plus", + temperature=0.5, + messages=[ + { + 'role': 'user', + 'content': user_query + } + ], + stream=True, # 启用流式响应 + stream_options={"include_usage": True} + ) + + full_response = "" # 用于存储完整的响应内容 + + for chunk in completion: + # 解析 chunk 数据 + if hasattr(chunk, 'to_dict'): + chunk_data = chunk.to_dict() + else: + chunk_data = json.loads(chunk.model_dump_json()) + + # 处理 usage 信息 + usage = chunk_data.get('usage') + if usage is not None: + completion_tokens = usage.get('completion_tokens', 0) + # prompt_tokens_details = usage.get('prompt_tokens_details', {}) #命中tokens ,取消注释可以print + # cache_hit = prompt_tokens_details.get('cached_tokens', 0) + # print("命中:"+str(cache_hit)) + # 处理 choices 信息 + choices = chunk_data.get('choices', []) + if choices: + choice = choices[0] + delta = choice.get('delta', {}) + content = delta.get('content', '') + if content: + full_response += content + # 实时打印内容(可以取消注释下面一行以实时输出) + # print(content, end='', flush=True) + if choice.get('finish_reason'): + # 处理完成原因(如果需要) + pass # 或者记录 finish_reason 以供后续使用 + + if need_extra: + return full_response, completion_tokens + else: + return full_response + + except Exception as exc: + # 提取错误代码 + error_code, error_code_string = extract_error_details(str(exc)) + logger.error(f"第 {attempt} 次尝试失败,查询:'{user_query}',错误:{exc}", exc_info=True) + + if error_code == 429: + if attempt <= max_retries: + token_count = get_total_tokens(user_query) + if token_count < 90000: #如果超过plus的qpm tpm,且user_query的tokens<90000,那么就调用turbo过渡一下。 + return qianwen_turbo(user_query,need_extra) + sleep_time = backoff_factor * (2 ** (attempt - 1)) # 指数退避 + logger.warning(f"错误代码为 429,将在 {sleep_time} 秒后重试...") + time.sleep(sleep_time) + else: + logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(429 错误)。") + break + else: + # 针对非 429 错误,只重试一次 + if attempt <= 1: + sleep_time = backoff_factor # 固定等待时间 + logger.warning(f"遇到非 429 错误(错误代码:{error_code} - {error_code_string}),将等待 {sleep_time} 秒后重试...") + time.sleep(sleep_time) + continue # 直接跳到下一次循环(即重试一次) + else: + logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(错误代码:{error_code} - {error_code_string})。") + break + + # 如果所有尝试都失败了,返回空字符串或默认值 + if need_extra: + return "", 0 + else: + return "" + +if __name__ == "__main__": + user_query1 = """该招标文件对响应文件(投标文件)偏离项的要求或内容是怎样的?请不要回答具体的技术参数,也不要回答具体的评分要求。请以json格式给我提供信息,外层键名为'偏离',若存在嵌套信息,嵌套内容键名为文件中对应字段或是你的总结,键值为原文对应内容。若文中没有关于偏离项的相关内容,在键值中填'未知'。 + 禁止内容: + 确保键值内容均基于提供的实际招标文件内容,禁止使用任何预设的示例作为回答。 + 禁止返回markdown格式,请提取具体的偏离相关内容。 + 示例1,嵌套键值对情况: + { + "偏离":{ + "技术要求":"以★标示的内容不允许负偏离", + "商务要求":"以★标示的内容不允许负偏离" + } + } + 示例2,无嵌套键值对情况: + { + "偏离":"所有参数需在技术响应偏离表内响应,如应答有缺项,且无有效证明材料的,评标委员会有权不予认可,视同负偏离处理" + } + """ + res = qianwen_plus(user_query1) + print(res) \ No newline at end of file diff --git a/flask_app/general/llm/qianwen_turbo.py b/flask_app/general/llm/qianwen_turbo.py new file mode 100644 index 0000000..7f7dd8d --- /dev/null +++ b/flask_app/general/llm/qianwen_turbo.py @@ -0,0 +1,1450 @@ +# -*- encoding:utf-8 -*- +import json +import logging +import os +import time + +from openai import OpenAI +from ratelimit import sleep_and_retry, limits +from flask_app.general.llm.大模型通用函数 import extract_error_details + + +@sleep_and_retry +@limits(calls=3, period=1) # 500万tpm,每秒最多调用6次,两个服务器分流就是3次 (plus超限后的保底手段,稳妥一点) +def qianwen_turbo(user_query, need_extra=False): + logger = logging.getLogger('model_log') # 通过日志名字获取记录器 + # 内部定义重试参数 + max_retries = 2 + backoff_factor = 2.0 + client = OpenAI( + api_key=os.getenv("DASHSCOPE_API_KEY"), + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" + ) + + for attempt in range(1, max_retries + 2): # +1 是为了包括初始调用 + try: + completion_tokens = 0 # 初始化 completion_tokens 为 0 + # 生成基于用户查询的响应 + completion = client.chat.completions.create( + model="qwen-turbo", + temperature=0.5, + messages=[ + { + 'role': 'user', + 'content': user_query + } + ], + stream=True, # 启用流式响应 + stream_options={"include_usage": True} + ) + full_response = "" # 用于存储完整的响应内容 + for chunk in completion: + # 解析 chunk 数据 + if hasattr(chunk, 'to_dict'): + chunk_data = chunk.to_dict() + else: + chunk_data = json.loads(chunk.model_dump_json()) + # 处理 usage 信息 + usage = chunk_data.get('usage') + if usage is not None: + completion_tokens = usage.get('completion_tokens', 0) + # prompt_tokens_details = usage.get('prompt_tokens_details', {}) #命中tokens ,取消注释可以print + # cache_hit = prompt_tokens_details.get('cached_tokens', 0) + # print("命中:"+str(cache_hit)) + # 处理 choices 信息 + choices = chunk_data.get('choices', []) + if choices: + choice = choices[0] + delta = choice.get('delta', {}) + content = delta.get('content', '') + if content: + full_response += content + # 实时打印内容(可以取消注释下面一行以实时输出) + # print(content, end='', flush=True) + if choice.get('finish_reason'): + # 处理完成原因(如果需要) + pass # 或者记录 finish_reason 以供后续使用 + + if need_extra: + return full_response, completion_tokens + else: + return full_response + except Exception as exc: + # 提取错误代码 + error_code, error_code_string = extract_error_details(str(exc)) + logger.error(f"第 {attempt} 次尝试失败,查询:'{user_query}',错误:{exc}", exc_info=True) + if error_code == 429: + if attempt <= max_retries: + sleep_time = backoff_factor * (2 ** (attempt - 1)) # 指数退避 + logger.warning(f"错误代码为 429,将在 {sleep_time} 秒后重试...") + time.sleep(sleep_time) + else: + logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(429 错误)。") + break + elif error_code == 400 and error_code_string in [ + 'data_inspection_failed', 'ResponseTimeout', 'DataInspectionFailed', + 'response_timeout', 'request_timeout', "RequestTimeOut" + ]: + if attempt == 1: # 只重试一次 + logger.warning(f"错误代码为 400 - {error_code_string},将立即重试...") + continue # 直接跳到下一次循环(即重试一次) + else: + logger.error( + f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(400 - {error_code_string})。") + break + else: + # 对于非 429 和非特定 400 错误,不进行重试,直接抛出异常 + logger.error( + f"遇到非 429 或非 'data_inspection_failed...' 的 400 错误(错误代码:{error_code}),不进行重试。") + break + # 如果所有尝试都失败了,返回空字符串或默认值 + if need_extra: + return "", 0 + else: + return "" +if __name__ == "__main__": + user_query=""" + 请根据货物标中采购要求部分的内容,告诉我交通信号灯技术要求下的信号灯灯杆的技术参数或采购要求是什么。请以 JSON 格式返回结果,键名为"交通信号灯技术要求.信号灯灯杆",键值为一个列表,列表中包含若干描述"交通信号灯技术要求下的信号灯灯杆"的技术参数或采购要求或功能说明的字符串,请按原文内容回答,保留三角▲、五角★和序号,不可擅自增删内容,尤其是不可擅自添加序号。 + +要求与指南: +1. 你的键值应该全面,不要遗漏。 + -a.若技术参数或采购要求在表格中,那么单元格内的内容基本都要涵盖 + -对于单元格内以序号分隔的各条参数要求,应逐条提取,并分别作为键值中的字符串列表项。 + -对于无序号标明且在同一单元格内的参数要求或功能说明,也要根据语义分别添加进键值中。 + -b.若技术参数或采购要求在正文部分,应准确定位到与目标货物(设备、系统、功能模块)相关的内容,将其后的技术参数或采购要求或功能说明完整提取,逐一添加到键值的字符串列表中,不得擅自添加或修改序号。 +2. 如果存在嵌套结构,且原文为Markdown 的表格语法,如'摄像机|有效像素|≥900W像素', 请不要返回该Markdown语法,而是使用冒号':'将相关信息拼接在一起,生成一条完整且清晰的技术参数(或采购要求)描述,作为列表中的一个字符串。如"摄像机:有效像素:≥900W像素"。 +3. 字符串中的内容为具体的技术参数要求或采购要求,请不要返回诸如'(1)高清录像功能'这种标题性质且不能体现要求的内容。 +4. 如果该货物没有相关采购要求或技术参数要求,键值应为空列表[]。 + +### 示例输出1如下: +{{ + "摄像机控制键盘": [ + "1、▲支持串行 RS232/RS422 和 IP 混合控制,允许在一个控制器上使用 RS232/RS422/IP 控制单个系统中的摄像机;", + "2、支持 2 组 RS422 串口 VISCA 协议菊花链控制 2x7 台摄像机。", + "★能够自动对焦,提供检测报告" + ] +}} + +### 示例输出2如下(包含嵌套结构): +{{ + "摄像机": [ + "摄像机:有效像素:≥900W像素", + "摄像机:最低照度:彩色≤0.001lx", + "协议:routes 接口开放:具备;▲支持标准 ONVIF 协议与第三方厂家设备进行互联;支持 GB/T28181;应提供 SDK" + ] +}} + +文件内容: +购法实施条例》、《政府采购货物和服务招标投标管理办法》及相关法律法规 + +43. 政府采购合同的履行、违约责任和解决争议的方法等适用《合同法》 + +## 十二、招标文件的解释权 + +44. 招标文件的最终解释权为采购人、分散采购机构所有。 + +## 第三章项目技术、服务及商务要求 + +### 相关技术标准 + +本技术规格依据以下技术标准编制,技术规格中仅列举了主要的技术指标及项目,其它指标及项目要求详见相应技术标准。 + +1)《中华人民共和国道路交通安全法实施条例》 + +2)《城市道路交通设施设计规范》(GB 50688-2011,2019 年修订版 + +3)《道路交通标志和标线》(GB 5768.2-2009 + +4)《道路交通标志反光膜》(GB/T18833-2012 + +5)《路面标线涂料》(JT/T280-2004 + +6)《道路交通标线质量要求和检测方法》(GB/T 16311-2009 + +7)《道路交通信号灯设置与安装规范》(GB 14886-2016 + +8)《道路交通信号控制机》(GB 25280-2010 + +9)《公路交通安全设施设计技术规范》(JTG D81-2017 + +10)《闯红灯自动记录系统通用技术条件》(GA/T496-2014 + +11)《视频安防监控系统工程设计规范》(GB50395-2007 + +12)《视频安防监控系统技术要求》(GA/T367-2001) + +13)《道路交通安全违法行为图像取证技术规范》(GA/T832-2014) + +14)《机动车号牌图像自动识别技术规范》(GA/T833-2016) + +15)《道路车辆智能监测记录系统通用技术条件》(GA/T497-2016 + +16)《公安交通指挥系统工程建设通用程序和要求》(GA/T651-2014 + +17)《公安交通管理外场设备基础设施施工通用要求》(GA/T652-2017 + +18)《安全防范工程技术标准》(GB50348-2018 + +19)《建筑物防雷设计规范》(GB50057-2010 + +20)《光纤通信系统通用规范》(SJ 20552-1995 + +21)《安全防范工程程序与要求》(GA/T75-1994 + +22)《安全防范系统验收规则》(GA308-2001 + +23)《安全防范系统通用图形符号》(GA/T74-2017 + +24)其它相关技术规范与标准 + +### 交通标线技术要求 + +#### 技术要求 + +1)热熔标线技术规范及要求。参考标准 + +1.投标货物必须符合中华人民共和国公共安全行业标准“GA/T298—2001《道路标线涂料》”、交通行业标准“JT/T280—2004《路面标线涂料》”及“GB/T24722《路而标线用玻璃珠》”的规范要求,重点指标要求如下 + + + + + + + + + + + + + + +
检测项目技术指标
反光型凸起型
密度(g/cm3)1.8-2.3
软化点(℃)90-125 ≥100
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
不粘胎干燥时间
涂抹外观涂膜冷凝后应无皱纹、斑点、起泡、裂纹、脱落及表面发粘等现象,涂膜颜色和外观应与标准板差异不大。
抗压轻度
耐磨性(mg)负载1kg200 转后减重——
耐水性经水浸泡24 小时后无异常
耐碱性在氢氧化钙饱和溶液中浸24h 无异常现象
流动度(S) ——
玻璃珠含量(%)▲≥20
色度性能白色色品坐标(x, y) 在以下四角点色品坐标组成的四边形内(0.350,0.300);(0.290,0.340)(0.360,0.310);(0.320,0.370)
亮度因素▲≥0.35
+ +2.道路标线施划施工内容必须符合“GB5768—2009 中《道路标线》”的规范要求 + +3.标线质量要求 + +①投标人必须提供施工使用的热熔涂料及玻璃珠的相关质量证明文件(检测报告等) + +▲②热熔标线旧标线的清除、采用高压水除线 + +★③热熔标线施划,标线表面加铺玻璃微珠,标线涂层厚度1.8mm±0.2mm + +4.标线相关计量说明 + +4.1.本项目价格形式为固定单价,最终计量结算,按照工程量清单单价据实结算 + +5.道路热熔标线质保期12 个月 + +### 交通标志技术要求 + +#### 技术要求 + +##### 1.标志牌铝板技术标准: + +①标志牌所采用铝板技术标准执行GB/T38/80—06 + +★②标志牌版面采用3mm 厚的铝板 + +##### 2.标志牌版面反光膜技术标准 + +①标志牌版面反光膜技术标准GB/T18833)—2012《道路交通反光膜》 + +★②标志牌反光膜采用Ⅳ类反光膜 + +③版面字体采用电脑刻字技术,标志版面颜色应符合GB5768—2017 规定 + +湖北众恒永业工程项目管理有限公司广水分公司编制 + +## 注:指路标志板面内容由采购方确认后制作 + +④标志牌版面反光膜质保期应不少于10 年。(投标人需在投标文件中作出承诺 + +## 3.标志牌杆件材料技术标准 + +★①标志标牌杆件立柱采用热浸镀锌内外表面防腐镀锌处理,热镀锌后再进行喷塑处理,应符合国家标准要求。 + +★②标志标牌杆件F 悬臂横梁采用热浸镀锌内外表面防腐镀锌处理,热镀锌后再进行喷塑处理,应符合国家标准要求。 + +★③标志标牌立柱和横梁采用无缝钢管。交通标志的连接件包括连接标志板滑槽与横梁和抱箍和螺栓、螺母,以及连接标志法兰盘与基础的地脚螺栓和螺母、专用不锈钢钢带等件,其材料的外形尺寸和机械性能应符合《道路交通标志板及支撑件》(GB/T23827-2009)相应标准要求。 + +## 4.标志标牌安装施工工艺技术标准 + +①标志标牌安装施工工艺必须符合“GB5768—2017 中《道路标志标线安装施工》”及《城市道路交通报纸和标线设置》(GB51038)的规范要求。 + +★②标志板与标志杆采用抱箍连接,抱箍必须经过热镀锌处理 + +## 5.标志标牌安装施工安全技术标准 + +①交通标志标牌安装位置准确,角度符合要求,且安装牢固 + +②严格执行交通安全维护与施工安全防护。标志基础应提前完成好养护,大型标志杆安装、大型标识标牌安装均应采用吊车、升降车配合人工完成,其他采用人工辅以小型机械施工作业。 + +③施工、保修符合现行有效的国家有关质量标准及实施规范 + +6.道路标志标牌质保期12 个月 + +## 交通信号灯技术要求 + +## 交通信号灯具 + +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、信号灯杆杆体底部应焊接固定法兰盘,法兰盘与杆体之间应均匀焊接加强筋 + +9、一体式人行信号灯采用整灯嵌入式设计、结构紧凑、方便拆装、便于维护。杆体前后金属面板喷塑处理,两侧铝型材包边。 + +## 交通信号机 + +★应采用区域控制信号机,并应与广水市交通信号控制系统兼容,信号机能接入已有系统平台,实现联网优化功能。 + +## 1、控制功能 + +(1)区域协调控制:可对单个孤立交叉口、干道多个交叉口和关联性较强的交叉口群进行综合性地信号控制。 + +2)线性协调控制:可对干道多个相邻交叉口进行协调控制 + +(3)多时段控制:可根据交叉口的交通状况,将每天划分为多个不同的时段,每个时段配置不同的控制方案,能设置至少10 个时段、10 种以上不同控制方案,能根据不同周日类型对方案进行调整。信号机能够根据内置时钟选择各个时段的控制方案,实现交叉口的合理控制。 + +(4)感应控制:信号机能根据检测到车辆达到情况,在保证最小安全绿灯时间的前提下,调整感应方向的绿信比参数,实现路口的最佳配时,保证交叉口的通行顺畅。通过参数配置,在感应方向没有机动车请求的情况下,信号机能够跳过感应相位,直接放行下一相位。 + +(5)单点优化控制:信号机能根据检测的交通流信息,适当调整路口周期时长和绿信比分配,实现路口信号控制的最优方案。 + +(6)无缆线协调控制:信号机能够通过配置路口相位差,即使在不联网的条件下,依然实现各个路口的绿波协调控制效果。 + +(7)手动控制:在某些特殊情况下,使用者可以通过手动装置完成手动强制功能,使信号显示停留在任意相位(包括全红、黄闪);信号机也可响应来自监控中心操作终端或现场笔记本的手动控制指令。 + +(8)黄闪控制:信号机具有黄闪控制功能,可以通过手动控制实现黄闪,或者通过规定时段自动进入黄闪控制。另外,当信号机的硬件发生故障时,可以进入硬件故障黄闪。 + +(9)全红控制:信号机能够根据时间表调用信号机的全红控制方案,实现对交叉口的全红控制功能。路口信号机具备一键全红功能,即:触动信号机某一按钮即实现路口全红控制,该按钮应设置在手控箱中便于操作。中心控制软件具备一键全红功能,用法同上。 + +(10)公交优先控制:支持RFID、地磁、线圈等检测方式,支持多种公交优先控制策略。 + +11)黑灯:能够一键关闭所有信号灯。 + +(12)行人过街按钮:信号机支持行人按钮信号输入,可在路口和路段响应来自行人按钮的行人过街请求。 + +(13)溢出控制:信号机发现路口拥堵后,能够立即调整绿灯时间或其他指定灯色的方式,避免过多车辆涌入拥堵方向或快速放行,抑制拥堵扩散(或溢出)或加速疏导。 + +14)相位控制:至少8 个相位控制,可扩至16 个以上相位控制。 + +15)信号灯组输出:至少8 个独立信号组输出,可扩展至16 个以上独立信号组输出 + +## 2、采集功能 + +1)信号机支持接入线圈、地磁、视频、微波、超声波检测器、RFID 等多种检测方式 + +2)信号机支持交通信息采集与统计,并支持交通流量共享 + +## 3、运维功能 + +1)信号机能够自动检测地磁故障,若故障,能够自动上传故障信息至监控中心 + +(2)具有故障自检功能,如信号机死机时迅速做出反应重新启动信号机;出现绿灯冲突时,马上切换到黄闪状态,对绿灯冲突进行检测和处理,并记录绿灯冲突的灯组;对信号灯驱动部分和外线出现的故障以及信号机各主要部件的故障进行自动检测和记录。 + +(3)信号机支持检测机柜内电压状态指标,若出现异常情况,能够及时报警并上传中心控制系统。 + +(4)信号机主控板一旦发生故障后,信号机仍能够继续运行定周期方案,保障路口交通秩序,等待主控板故障排除后,自动恢复。 + +(5)信号机出现故障时应能按“上位机控制→无电缆协调控制→感应控制→定时控制→黄闪”实现降级。 + +## 4、通信功能 + +1)交通信号控制器支持有线、无线联网 + +(2)交通信号控制机应基于开放的通信协议,满足《交通信号控制机与上位机间的数据通信协议》(GB/T20999-2017)标准或NTCIP 通讯协议体系架构,符合度≥90%。 + +## 5、操作功能 + +(1)交通信号控制器必须提供维护软件,支持通过串口、网口连接。信号机侧面具备手动控制面板,能够在现场进行手动控制。 + +湖北众恒永业工程项目管理有限公司广水分公司编制 + +## 6、其他功能 + +(1)机动车灯按顺序的转换过程中无显示中断现象。人行横道灯绿灯时间能够灵活确定。绿闪、黄灯、全红时间设置为0 时,该灯色不应出现,且不会影响信号的正常转换。 + +(2)信号机从自动控制方式转入手动控制方式时,信号机应保持原有相位的最小安全时间,最小安全时间可根据路口实际情况设定;从手动控制方式(驻留或步进)转入自动控制方式时,信号状态不会突变,各相位信号应保持转换时刻的状态,至少保持最小安全时间。 + +(3)信号机采用的芯片具有精确的时钟,与中心系统联接后,系统可定时校准信号机时钟,采用具有时、分、秒、年、月、日、星期的晶体时钟计时,保证信号机时钟精度在1秒内。若信号机不与中心连接,配置GPS 接口,可通过GPS 接口进行精确的时钟校准,保证时钟分秒无差。停电时由电池保持时钟继续工作,采用锂电池作为后备电源。 + +(4)停电保护功能:自动保存修改的各项控制参数,停电后数据不会丢失。质保期:2年。 + +## 交通监控视频子系统 + +## 系统功能 + +## 1)高清录像功能 + +▲系统能实现24 小时高清视频录像功能。可以在白天或夜间有辅助光源的情况下实现清晰录像;视频编码格式至少支持H.264/ H.265;可自动记录车辆通过时间、地点、所在车道、违法类型等信息;录像中能清晰地反映车辆的颜色、车辆类型、运动轨迹,并提供录像查询、下载等功能。 + +## 2)云镜控制功能 + +▲至少具备监控前端设备切换、云台/快球控制器方向控制、焦距调节、镜头缩放、光圈调节、预置位设置、雨刷和电源开关控制、自定义辅助开关控制、监控前端设备锁定与解锁、云台/快球控制器的参数设定等功能。 + +3)巡检预警功能 + +系统可对城市进行全面综合交通视频监控;通过交通视频监控系统的巡检功能,定时不间断地对城市进行全面监控扫描。值班人员可以根据图像画面上所发出的报警信息,及时定点跟踪确认。第一时间进行力量调度,并对事件的发展情况和事态的全程变化状况全程跟踪、 + +实时录像、调查取证 + +## 4)警情核实功能 + +利用交通视频监控系统,可以准确地对城市报警情况进行核实。当接到报警信息后,可以将摄像头调整到报警位置,进行识别判断;确认报警信息是否属实。 + +## 5)救援指挥功能 + +交通视频监控系统由于位置高、监控距离远、视角广的特点,在发生某些特定事件救援时,可以有效地对救援点交通进行一个诊断,减少或者避免由于客观原因造成的事态扩大。 + +## 6)车辆布控功能 + +▲设备具备车辆布控功能,当监视画面中出现布控名单中的机动车时,设备可触发报警并跟踪,布控名单中可添加10000 个号牌信息 + +## 一体化高速球机 + +1 ▲用≥1.8 英寸红外型800 万像素逐行扫描图像传感器 + +2、光学变倍≥22 倍,焦距≥6.5\~143mm,支持H.265、H.264、MJPEG 视频编码 + +3、分辨率≥3840×2160,喷率≥30fpS,,亮度等级≥11 级 + +4、支持超低照度监控:彩色模式≤0.01lx,黑白模式≤0.003lx,具备三码流功能:主码流3840×2160、30 帧/秒、8Mbps;子码流1280×720、30 帧/秒、1Mbps;第三码流主码流3840×2160、30 帧/秒、1Mbps,码率设置为128Kbps\~8Mbps。 + +5、摄像机具备自动增益控制功能、自动白平衡调整功能、逆光补偿调整功能、日夜模式、电子快门、自动聚焦、断电记忆、定时启动、区域遮盖、自动定位、在线升级、断线自动重连。 + +6、▲支持前端存储功能 + +7、支持360°水平连续旋转,支持垂直-15°\~90°旋转 + +8、摄像机具备良好的电源适应性,在AC24±35%或DC24±35%范围内,能正常工作IP 防护等级≥IP67,环境温度满足-45\~70℃。 + +## 光纤收发器 + +1、1 路千兆以太网 + +2、单模单纤,光接口为FC 接口,满足实际传输距离要求 + +3、10/100/1000M 自适应以太网接口。 + +4、工作环境适应性强,满足全天候使用的要求 + +5、耐压≥300V + +## 交通诱导子系统 + +# 交通诱导屏 + +1、主要特性 + +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 + +2、技术参数 + +1)物理点间距:10mm + +2)物理密度:10000 点/m2 + +3)发光点颜色:1R1G + +4)基色:纯红+纯绿 + +5)模组尺寸:320mm*160mm + +6)刷新频率:≥800HZ + +7)工作电压:AC220V±10%,50Hz(三相五线制 + +8)平均功耗:350W/m2 + +9)最大功耗:≤700W/ m2 + +## 电子警察子系统 + +## 系统功能 + +## 1)闯红灯违法抓拍功能 + +★系统可以实现对单方向各车道闯红灯车辆的监测、图像抓拍等功能。闯红灯捕获率≥90%,每一违法记录拍摄连续3 张反映闯红灯过程的图片,其中第一个位置的图片反映机动车未到达停止线的情况,并能清晰辨别车辆类型、交通信号灯红灯、停止线;第二个位置的图片反映机动车已越过停止线的情况,并能清晰辨别车辆类型、号牌号码、交通信号灯红灯、停止线;第三个位置的图片反映机动车越过停止线继续前行的情况,并能清晰辨别车辆类型、交通信号灯红灯、停止线。 + +## 2)不按车道行驶记录功能 + +当车辆遇到“分向行驶车道”不按规定的转向、右转车辆占用直行车道,或在左转、右转车道上直行等情形,系统可以实现对此类违法行为的记录,以三张图片清晰、完整表现违法过程。 + +## 3)违章变道记录功能 + +▲系统能够对违法变道车辆进行记录,抓拍三张不同位置的图片以反映整个违法变道过程,其中第一张为车辆在初始车道行驶时抓拍的图片,第二张为压线行驶时抓拍的图片,第三张为变换到另一个车道上行驶时抓拍的图片。 + +## 4)闯禁令记录功能 + +系统能够对违反禁左、禁右、禁止掉头等通行的车辆,进行检测、抓拍记录与识别 + +## 5)卡口监测记录功能 + +系统能够准确捕获、记录车辆通行信息(车辆尾部的图片),对通过车辆的捕获率不小于99%。记录的车辆信息除包含图像信息外,还包括文本信息,如日期、时间(精确到秒)、地点、方向、号牌号码等。车辆信息写入关联数据库,并将相关文本信息叠加到图片上。 + +## 6)逆行记录功能 + +系统能够对逆向行驶的违法车辆进行检测、抓拍记录与识别 + +## 7)压线行驶记录功能 + +系统能够对压线行驶的违法车辆进行检测、抓拍记录与识别,其主要针对在连续一段时 + +间内压车道线行驶的车辆,此类车辆会影响前后车驾驶员的判断,干扰前后车的正常形式。 + +## 8)车身颜色识别功能 + +▲系统能够自动对车身深浅和颜色进行识别,可供用户根据车身颜色来查询通行车辆 + +## 9)车牌号码自动识别 + +系统能够对符合“GA36-2014”标准的民用车牌、新能源车辆、警用车牌、使领馆车牌的号牌自动识别能力。 + +## 10)图像防纂改功能 + +记录的原始图像信息具备防纂改功能,避免在传输存储、处理等过程中被认为篡改 + +## 11)测速功能 + +系统能够与测速设备配套使用,监控车辆行驶的速度,对超速行驶的车辆进行抓拍 + +## 12)未系安全带检测功能 + +★采用视频检测技术,对未系安全带行为进行检测,抓拍记录与识别 + +## 13)接打电话检测功能 + +采用视频检测技术,实现对前排驾驶人接打电话状态的检测,抓拍记录与识别 + +## 14)驾驶人面部特征记录功能 + +★在电子警察杆件上增加车辆正向采集的摄像机,可通过路口终端服务器实现驾驶人面部特征记录功能。可将违法行为与对应车辆的正向图片匹配起来,从而将违法行为固定到驾驶人,有效遏制驾驶分非法买卖现象,同时为公安交通管理和刑侦案件侦破提供技术支持。 + +## 15)车辆稽查布控功能 + +系统具备车辆交通安全违法行为监测报警和布控车辆自动比对报警功能,比对方式包括精确比对和模糊比对。 + +## 16)交通流量数据采集功能 + +系统能够按车道和时段进行车辆流量、平均速度、车辆类型、占有率、平均车头时距、平均排队长度、饱和度等数据的统计。所有统计数据应支持以报表形式输出。 + +## 17)高清录像功能 + +系统支持道路交通情况的实时视频录像存储,视频质量能清晰反映覆盖区域内行驶机动车的车牌号码。视频采用预分配存储机制,前端支持进行滚动存储7 天以上。 + +## 18)数据断点续传功能 + +系统支持断点续传功能。当遇到网络中断或其他故障时,车辆信息存储在前端设备中待故障排除后自动续传。 + +湖北众恒永业工程项目管理有限公司广水分公司编制 + +## 19)时间校准功能 + +按照《GA/T832-2014 道路交通安全违法行为图像取证技术规范》的要求,24h 内计时误差不超过1.0s,确保所有前端设备点位每日至少与电子警察中心系统时钟同步一次。 + +## 20)网络远程维护功能 + +系统可以实时查看前端设备的运行状态。能通过网络实现远程维护、远程设置和远程升级等功能。 + +## 20)黑白名单功能 + +▲系统支持车牌黑/白名单设置,最大可设置60 万条黑/白名单 + +## 21)连续闯红灯监测功能 + +▲支持连续闯红灯事件检测功能,对某一时间段内连续闯红灯事件进行检测,并自动上传报警信息。 + +## 高清视频摄像机 + +高清视频摄像机为核心产品 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术规格要求
1 摄像机有效像素≥900W 像素
最低照度彩色≤0.001lx
传感器类型≥1 英寸全局曝光COMS/GMOS/GS COMS
电子快门至少满足1/25s 至1/100,000s,可调
2 视频图像视频压缩标准至少支持H264、H265 等
视频分辨率≥4096×2160,向下可设置
视频流帧率≥25fps,至少双视频流
3 图片压缩方式JPEG
图像分辨率≥4096(H)×2160(V)
强光抑制具备
4 协议API 接口开放▲具备;支持标准ONVIF 协议与第三方厂家设备进行互联;支持GB/T28181;应提供SDK
5 接口通讯接口≥1 个RJ45,10M/100M/1000M 自适应以太网电口;≥1 个RS-485 接口
前端存储卡嵌入式,支持断网时本地存储,裸容量≥128GB
功能具备其他功能应具备I/O 触发、RS-485 触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光
具备AI 深度学习算法和GPU 芯片
6 高清工业级镜头光圈、聚焦手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于900 万像素,边缘解像力不低于中心60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具
备根据环境自动切换功能
7 防护罩防护罩类型室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。
防护等级≥IP66
+ +LED 补光灯 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术参数要求
1 配置方式每个车道配置≥1 台;补光装置必须与高清摄像设备高度匹配
2 LED 管芯采用超高亮大功率白光LED 管芯,灯珠数量不少于20 颗
3 功耗30W/车道≤单台平均功耗≤50W/车道,可调
4 峰值光照度≤300lx
(基准轴)
5 峰值光照度应大于等于基准轴上有效光照度的50%
(补光区)
6 平均光照度
7 闪光频率;补光装置应能与集成式高清摄像设备同步
8 有效补光距离≥25m
9 最大点亮时间≤4ms(可调节)
10 控制方式电平,同步触发方式
11 安全性在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染
12 使用寿命≥50000 小时
13 防护等级不低于IP65
14 其它应配置光栅装置或遮光阻断装置
+ +## 光纤收发器 + +1、1 路千兆以太网 + +2、单模单纤,光接口为FC 接口,满足实际传输距离要求 + +3、10/100/1000M 自适应以太网接口。 + +4、工作环境适应性强,满足全天候使用的要求 + +5、耐压≥300V + +## 交换机 + +1、交换容量≥6Gbps,包转发率≥7Mpps;MAC 地址列表≥8K;应具备线性转发能力; + +2、应至少具有8 个10/100/1000M 自适应以太网接口和至少2 个1000M 光口 + +3、以太网光端口传输距离应不小于40km,以太网光模块为单芯双向光模块,光口接口类型为LC 型接口,光模块连接单模光纤; + +4、至少支持IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z IEEE802.3x 等协议; + +5、应具有IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持4 个VLAN 划分; + +6、应至少支持三层动态路由协议 + +7、应具有IEEE802.1p_QOS 功能 + +8、应具有IGMP 静态组播、端口聚合、端口镜像等功能 + +9、IP40 以上等级防护 + +10、应采用无风扇设计 + +11、应具有网管功能 + +## 红绿灯信号检测器 + +每路口配置1 套,至少能检测12 路独立红灯信号,红灯信号检测准确率为100% + +## 终端服务器 + +1、结构形式:采用嵌入式架构 + +2、操作系统:嵌入式操作系统 + +3、▲接入路数:提供≥12 路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等; + +4、主机存储:内置SATA 接口;配置存储容量≥16T 硬盘 + +5、网络接口:提供≥8 个RJ45 1000M 网络接口 + +6、其他接口:提供RS232、RS485、外置USB 接口、VGA 接口等 + +7、访问操作:支持Web 操作访问 + +8、▲接口协议:至少支持ONVIF,GB/T28181 等 + +9、API 接口开放支持;支持标准ONVIF 协议与第三方厂家设备进行互通;支持GB/T 28181。 + +10、▲支持套牌车检测,可将抓拍图片与本地历史数据进行车辆特征比对分析,检测出 + +套牌车辆,同时给出告警提示 + +## 交通卡口子系统 + +## 系统功能 + +对监控路段的车辆、车道进行全天候实时的监控并记录相关图像、视频数据。主要实现以下功能: + +1)卡口记录功能:捕获正常行驶车辆的过车图片,抓拍率≥99% + +2)逆行记录功能:对逆向行驶的违法车辆进行检测、抓拍记录与识别 + +(3)压线行驶记录功能:对压线行驶的违法车辆进行检测、抓拍记录与识别,其主要针对在连续一段时间内压车道线行驶的车辆,此类车辆会影响前后车驾驶员的判断,干扰前后车的正常行驶; + +(4)车身颜色识别功能:可自动对车身深浅和颜色进行识别,可供用户根据车身颜色来查询通行车辆; + +(5)车牌号码自动识别:对符合“GA36-2014”标准的民用车牌、新能源车辆、警用车牌、使领馆车牌的号牌自动识别能力; + +(6)闯禁行记录功能:对违反禁止通行的车辆,进行检测、抓拍记录与识别; + +(7)▲图像防纂改功能:记录的原始图像信息具备防纂改功能,避免在传输存储、处理等过程中被人为篡改; + +(8)测速功能:与测速设备配套使用,监控车辆行驶的速度,对超速行驶的车辆进行抓拍; + +(9)★未系安全带检测功能:采用视频检测技术,对未系安全带行为进行检测,抓拍记录与识别; + +(10)接打电话检测功能:采用视频检测技术,实现对前排驾驶人接打电话状态的检测,抓拍记录与识别; + +(11)★人脸特征抠图:采用视频检测技术对驾驶室人脸特征进行检测并将人脸特征抠出,为公安交通管理和刑侦案件侦破提供技术支持。 + +(12)▲支持混合抓拍模式,设备支持正面/侧面/背面行人(包括成年人和儿童)的抓拍;支持对骑自行车、骑三轮车、骑电动车、踩平衡车、骑车带人等 + +非机动车的抓拍;支持对轿车、客车、面包车、货车、卡车、摩托车等机动车的抓拍 + +高清视频抓拍像机 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术规格要求
1 摄像机有效像素≥900W 像素
最低照度彩色≤0.001lx
传感器类型≥1 英寸全局曝光COMS/GMOS/GS COMS
电子快门至少满足1/25s 至1/100,000s,可调
2 视频图像视频压缩标准至少支持H264、H265 等
视频分辨率≥4096×2160,向下可设置
视频流帧率≥25fps,至少双视频流
3 图片压缩方式JPEG
图像分辨率≥4096(H)×2160(V)
强光抑制具备
4 协议API 接口开放具备;支持标准ONVIF 协议与第三方厂家设备进行互联;支持GB/T28181;应提供SDK
5 接口通讯接口≥1 个RJ45,10M/100M/1000M 自适应以太网电口;≥1个RS-485 接口
前端存储卡嵌入式,支持断网时本地存储,裸容量≥128GB
功能具备其他功能应具备I/O 触发、RS-485 触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光
具备AI 深度学习算法和GPU 芯片
6 高清工业级镜头光圈、聚焦手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于900 万像素,边缘解像力不低于中心60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能
7 防护罩防护罩类型室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。
防护等级≥IP66
+ +## 补光灯 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术参数要求
1 配置方式每个车道配置≥1 台;补光装置必须与高清摄像设备高度匹配
2 LED 管芯采用超高亮大功率白光LED 管芯,灯珠数量不少于20 颗
3 功耗30W/车道≤单台平均功耗≤50W/车道,可调
4 峰值光照度≤300lx
(基准轴)
5 峰值光照度应大于等于基准轴上有效光照度的50%
+ +湖北众恒永业工程项目管理有限公司广水分公司编制 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术参数要求
(补光区)
6 平均光照度
7 闪光频率光装置应能与集成式高清摄像设备同步
8 有效补光距离≥25m
9 最大点亮时间≤4ms(可调节)
10 控制方式电平,同步触发方式
11 安全性在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染
12 使用寿命≥50000 小时
13 防护等级不低于IP65
14 其它应配置光栅装置或遮光阻断装置
+ +## 闪光灯 + +1、色温范围5500±500K + +2、补光距离16m\~30m + +3、回电时间≤60ms,满足相机2 张连拍需求 + +4、闪光灯寿命>500 万次 + +5、自带光敏控制,可根据环境亮度自动调节闪光强度 + +6、防护等级IP66 + +7、在-20℃\~70℃温度范围内均能正常工作 + +## 光纤收发器 + +1、1 路千兆以太网 + +2、单模单纤,光接口为FC 接口,满足实际传输距离要求 + +3、10/100/1000M 自适应以太网接口。 + +4、工作环境适应性强,满足全天候使用的要求 + +5、耐压≥300V + +## 交换机 + +1、交换容量≥6Gbps,包转发率≥7Mpps;MAC 地址列表≥8K;应具备线性转发能力 + +2、应至少具有8 个10/100/1000M 自适应以太网接口和至少2 个1000M 光口 + +3、以太网光端口传输距离应不小于40km,以太网光模块为单芯双向光模块,光口接口类型为LC 型接口,光模块连接单模光纤; + +4、至少支持IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x + +湖北众恒永业工程项目管理有限公司广水分公司编制 + +等协议 + +5、应具有IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持4 个VLAN 划分 + +6、应至少支持三层动态路由协议 + +7、应具有IEEE802.1p_QOS 功能 + +8、应具有IGMP 静态组播、端口聚合、端口镜像等功能 + +9、IP40 以上等级防护 + +10、应采用无风扇设计 + +11、应具有网管功能 + +## 终端服务器 + +1、结构形式:采用嵌入式架构 + +2、操作系统:嵌入式操作系统 + +3、接入路数:提供≥12 路高清摄像机视频存储、过车记录存储、图片存储、数据上传、视频流转发等; + +4、主机存储:内置SATA 接口;配置存储容量≥16T 硬盘 + +5、网络接口:提供≥8 个RJ45 1000M 网络接口 + +6、其他接口:提供RS232、RS485、外置USB 接口、VGA 接口等 + +7、访问操作:支持Web 操作访问 + +8、接口协议:至少支持ONVIF,GB/T28181 等 + +9、API 接口开放支持;支持标准ONVIF 协议与第三方厂家设备进行互通;支持GB/T 28181。 + +## 区间测速子系统 + +## 系统功能 + +1)卡口记录功能:捕获正常行驶车辆的过车图片,抓拍率≥95% + +2)逆行记录功能:对逆向行驶的违法车辆进行检测、抓拍记录与识别 + +(3)压线行驶记录功能:对压线行驶的违法车辆进行检测、抓拍记录与识别,其主要针对在连续一段时间内压车道线行驶的车辆,此类车辆会影响前后车驾驶员的判断,干扰前后车的正常形式; + +(4)车身颜色识别功能:可自动对车身深浅和颜色进行识别,可供用户根据车身颜色来查询通行车辆; + +(5)车牌号码自动识别:对符合“GA36-2014”标准的民用车牌、新能源车辆、警用车牌、使领馆车牌的号牌自动识别能力; + +(6)▲闯禁行记录功能:对违反禁止通行的车辆,进行检测、抓拍记录与识别; + +(7)图像防纂改功能:记录的原始图像信息具备防纂改功能,避免在传输存储、处理等过程中被认为篡改; + +(8)★测速功能:与测速设备配套使用,监控车辆行驶的速度,对超速行驶的车辆进行抓拍; + +(9)未系安全带检测功能:采用视频检测技术,对未系安全带行为进行检测,抓拍记录与识别; + +(10)接打电话检测功能:采用视频检测技术,实现对前排驾驶人接打电话状态的检测,抓拍记录与识别; + +(11)人脸特征抠图:采用视频检测技术对驾驶室人脸特征进行检测,并将人脸特征抠出,为公安交通管理和刑侦案件侦破提供技术支持。 + +高清视频抓拍像机 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术规格要求
1 摄像机有效像素≥900W 像素
最低照度彩色≤0.001lx
传感器类型≥1 英寸全局曝光COMS/GMOS/GS COMS
电子快门至少满足1/25s 至1/100,000s,可调
2 视频图像视频压缩标准至少支持H264、H265 等
视频分辨率≥4096×2160,向下可设置
视频流帧率≥25fps,至少双视频流
3 图片压缩方式JPEG
图像分辨率≥4096(H)×2160(V)
强光抑制具备
4 协议API 接口开放具备;支持标准ONVIF 协议与第三方厂家设备进行互联;支持GB/T28181;应提供SDK
5 接口通讯接口≥1 个RJ45,10M/100M/1000M 自适应以太网电口;≥1个RS-485 接口
前端存储卡嵌入式,支持断网时本地存储,裸容量≥128GB
功能具备其他功能应具备I/O 触发、RS-485 触发、视频触发,支持电源同步;支持频闪式卜光装置和脉冲式补光装置同步补光
具备AI 深度学习算法和GPU 芯片
6 高清工业级镜头光圈、聚焦手动光圈;焦距应可根据车道宽度及抓拍距离进行调整设置,要求中心成像圆内解像力不小于900 万像素,边缘解像力不低于中心60%,镜头的成像尺寸应与摄像机成像靶面尺寸相等或略大。镜头应配置电动偏振镜,具备根据环境自动切换功能
7 防护罩防护罩类型室外型防护罩,含底座;具备隔热防潮、防水、防尘、防腐、防震等功能;具有加热器、支架、遮阳罩等,具有良好的密封性和恒温等功能。
防护等级≥IP66
+ +## 补光灯 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号指标项技术参数要求
1 配置方式每个车道配置≥1 台;补光装置必须与高清摄像设备高度匹配
2 LED 管芯采用超高亮大功率白光LED 管芯,灯珠数量不少于20 颗
3 功耗30W/车道≤单台平均功耗≤50W/车道,可调
4 峰值光照度≤300lx
(基准轴)
5 峰值光照度应大于等于基准轴上有效光照度的50%
(补光区)
6 平均光照度
7 闪光频率补光装置应能与集成式高清摄像设备同步
8 有效补光距离≥25m
9 最大点亮时间≤4ms(可调节)
10 控制方式电平,同步触发方式
11 安全性在保证瞬时亮度的前提下,必须进行防炫目处理,不会造成光污染
12 使用寿命≥50000 小时
13 防护等级不低于IP65
14 其它应配置光栅装置或遮光阻断装置
+ +## 闪光灯 + +1、色温范围5500±500K + +2、补光距离16m\~30m + +3、回电时间≤60ms,满足相机2 张连拍需求 + +4、闪光灯寿命>500 万次 + +5、自带光敏控制,可根据环境亮度自动调节闪光强度 + +6、防护等级IP66 + +7、在-20℃\~70℃温度范围内均能正常工作 + +## 光纤收发器 + +1、1 路千兆以太网 + +2、单模单纤,光接口为FC 接口,满足实际传输距离要求 + +3、10/100/1000M 自适应以太网接口。 + +4、工作环境适应性强,满足全天候使用的要求 + +5、耐压≥300V + +## 交换机 + +1、交换容量≥6Gbps,包转发率≥7Mpps;MAC 地址列表≥8K;;应具备线性转发能力 + +2、应至少具有8 个10/100/1000M 自适应以太网接口和至少2 个1000M 光口 + +3、以太网光端口传输距离应不小于40km,以太网光模块为单芯双向光模块,光口接口类型为LC 型接口,光模块连接单模光纤; + +4、至少支持IEEE802.1p、IEEE802.1q、IEEE802.3、IEEE802.3u、IEEE802.3z、IEEE802.3x 等协议; + +5、应具有IEEE802.1Q VLAN,应实现信号控制独立传输,至少支持4 个VLAN 划分 + +6、应至少支持三层动态路由协议 + +7、应具有IEEE802.1p_QOS 功能 + +8、应具有IGMP 静态组播、端口聚合、端口镜像等功能 + +9、IP40 以上等级防护 + +10、应采用无风扇设计 + +11、应具有网管功能 + +## 终端服务器 + +1、结构形式:采用嵌入式架构 + +2、操作系统:嵌入式操作系统 + +3、接入路数:提供≥8 路高清摄像机视频存储、过车记录存储、图片存储、数据上传视频流转发等; + +4、主机存储:内置SATA 接口;配置存储容量≥16T 硬盘 + +5、网络接口: 提供≥8 个RJ45 1000M 网络接口 + +6、其他接口:提供RS232、RS485、外置USB 接口、VGA 接口等 + +7、访问操作:支持Web 操作访问 + +8、接口协议:至少支持ONVIF,GB/T28181 等 + +9、API 接口开放支持;支持标准ONVIF 协议与第三方厂家设备进行互通;支持GB/T 28181。 + +## 后台 + +## 接入服务器 + +1、机架式服务器 + +2、处理器:至少配置2 颗单颗10 核CPU,单核CPU 主频≥2.0GHz; + +3、内存:配置128GB DDR4 内存 + +4、硬盘:配置6 块1.2T SAS 硬盘,转速≥10Krpm + +5、RAID:配置RAID 控制器,支持RAID0、1、10、1E、5、50、60 等 + +6、网络:配置双千兆网卡 + +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 + +# 其他设备要求 + +# 室外挂箱 + +1、采用悬挂式安装方式,悬挂于杆件立柱,高度应确保机箱下边缘距离地面净高2.5米以上。设备机箱安装后不得侵入机动车道建筑界限以内,不得影响车辆正常通行。设备机箱应安装牢固; + +2、设备机箱表面应经过考漆处理,应具备防锈蚀、防盐雾、防霉菌能力 + +3、应能摆放通信接入端设备。机箱内部空间应足够大,能确保设备、装置的合理摆放,设有存放用户手册、说明书、接线图、维修记录等资料的存储盒,并有适当空间预留。机箱空间应有利于机箱内各设备单元的散热、安装、使用和维修,同时应提供设备辅助散热措施,提高系统环境适应能力; + +4、设备机箱的结构应能防雨并能降低灰尘及有害物质的侵入,机箱门盖应有溢水槽机箱门内侧应配备密封条,机箱顶部应具有防积水措施。机箱防护等级应达到IP55 以上; + +5、机箱结构应具有足够的机械强度,应能承受正常条件下可预料到的运输、安装、搬运、维护等过程中的操作; + +6、机箱门的最大开启角度应大于120°。机箱门锁应采用保险柜天地锁式的结构设计防止被非法打开,门锁至少可对上、下及左右侧中的一侧进行缩栓式保护,应具备较强的设备防砸、防盗能力。机箱应具有防盗报警功能,机箱在非正常状态下开启时能够报警提示。机箱门接缝处有耐久且有弹性的密封垫,密封垫连续设置,无间断接口。机柜门锁上后,无松动、变形现象; + +7、设备机箱内设应置有具备稳压、过载、漏电、短路保护功能的电源开关和防雷保护功能的电源浪涌保护器。在熔断器和电源开关等处应有警告标志。机箱内合适位置配备接地铜排,接地铜排的截面应不小于100 mm2,接地端子应进行防腐处理。并应设置接地标志;接地铜排应保证良好接地,接地线截面积应不小于16mm2; + +8、机箱内应配备不少于2 路单相2 孔扁圆电源插座、2 路单相3 孔扁圆电源插座 + +9、电源开关:应具有稳压、短路、过载、漏电保护;电源保护响应时间应为纳秒级;开关的额定电压、额定电流值应满足设备正常运行的要求;机械寿命应不少于20000 次;具有良好的散热性能。 + +10、室外大机箱需满足上述使用外,还应可安装前端管理主机 + +## 交通管道要求 + +过街管道主要垂直于道路中线埋设,可开挖路段采用DN90 镀锌钢管,不宜开挖路段根据现场情况采用拖拉管(DN90 PE 管)。路口必须在各方向埋设双管。非过街管道采用PE 双壁波纹管。 + +干线(纵向)路段两接线井之间最大距50m + +管道其他技术参数应满足现行的《YDT841 地下通信管道用塑料管》要求,机动车道和非机动车道下管道埋设深度(管顶至路面)应≥0.7m,人行道及绿化带下管道埋设深度(管顶至路面)应≥0.5m。如不能达到上述埋设深度要求应采取混凝土包封或采用钢管等保护措施。管道敷设的坡度应为0.3%-0.4%,不得小于0.25%。其他敷设要求应参照《市政公用工程细部构造做法(湖北省)》中《交通管道预埋断面图》做法。 + +交通管道开挖后应按原有道路或绿化进行恢复,管线尽量敷设于人行道上,不影响后续的绿化园林施工。 + +具体详见工程量清单(附表 + +## 第四章资格审查方法及标准 + +根据《政府采购法》、《政府采购法实施条例》、《政府采购货物和服务招标投标管理 + """ + res=qianwen_turbo(user_query) + print(res) \ No newline at end of file diff --git a/flask_app/general/llm/多线程提问.py b/flask_app/general/llm/多线程提问.py index 1e893b6..71c7509 100644 --- a/flask_app/general/llm/多线程提问.py +++ b/flask_app/general/llm/多线程提问.py @@ -1,37 +1,12 @@ -# 基于知识库提问的通用模板, -# assistant_id import re import queue import concurrent.futures import time - from dashscope import Assistants, Messages, Runs, Threads from llama_index.indices.managed.dashscope import DashScopeCloudRetriever - -from flask_app.general.llm.doubao import read_txt_to_string -from flask_app.general.llm.通义千问long_plus import qianwen_long, upload_file, qianwen_plus - -prompt = """ -# 角色 -你是一个文档处理专家,专门负责理解和操作基于特定内容的文档任务,这包括解析、总结、搜索或生成与给定文档相关的各类信息。 - -## 技能 -### 技能 1:文档解析与摘要 -- 深入理解并分析${documents}的内容,提取关键信息。 -- 根据需求生成简洁明了的摘要,保持原文核心意义不变。 - -### 技能 2:信息检索与关联 -- 在${documents}中高效检索特定信息或关键词。 -- 能够识别并链接到文档内部或外部的相关内容,增强信息的连贯性和深度。 - -## 限制 -- 所有操作均需基于${documents}的内容,不可超出此范围创造信息。 -- 在处理敏感或机密信息时,需遵守严格的隐私和安全规定。 -- 确保所有生成或改编的内容逻辑连贯,无误导性信息。 - -请注意,上述技能执行时将直接利用并参考${documents}的具体内容,以确保所有产出紧密相关且高质量。 -""" -prom = '请记住以下材料,他们对回答问题有帮助,请你简洁准确地给出回答,不要给出无关内容。${documents}' +from flask_app.general.llm.大模型通用函数 import read_txt_to_string +from flask_app.general.llm.通义千问long import qianwen_long, upload_file +from flask_app.general.llm.qianwen_plus import qianwen_plus def read_questions_from_file(file_path): questions = [] diff --git a/flask_app/general/llm/大模型通用函数.py b/flask_app/general/llm/大模型通用函数.py new file mode 100644 index 0000000..90e86c8 --- /dev/null +++ b/flask_app/general/llm/大模型通用函数.py @@ -0,0 +1,151 @@ +import ast +import os +import re +from functools import wraps + +import PyPDF2 +from ratelimit import sleep_and_retry, limits +import requests +from flask_app.general.读取文件.clean_pdf import extract_common_header, clean_page_content + +@sleep_and_retry +@limits(calls=10, period=1) # 每秒最多调用20次,qpm=1200万,两个服务器分流,每个10 +def rate_limiter(): + pass # 这个函数本身不执行任何操作,只用于限流 + +# 创建一个共享的装饰器 +def shared_rate_limit(func): + @wraps(func) + def wrapper(*args, **kwargs): + rate_limiter() # 通过共享的限流器 + return func(*args, **kwargs) + return wrapper + +def extract_error_details(error_message): + """ + 从错误消息中提取错误代码和内部错误代码。 + 假设错误消息的格式包含 'Error code: XXX - {...}' + """ + # 提取数值型错误代码 + error_code_match = re.search(r'Error code:\s*(\d+)', error_message) + error_code = int(error_code_match.group(1)) if error_code_match else None + + # 提取内部错误代码字符串(如 'data_inspection_failed') + error_code_string = None + error_dict_match = re.search(r'Error code:\s*\d+\s*-\s*(\{.*\})', error_message) + if error_dict_match: + error_dict_str = error_dict_match.group(1) + try: + # 使用 ast.literal_eval 解析字典字符串 + error_dict = ast.literal_eval(error_dict_str) + error_code_string = error_dict.get('error', {}).get('code') + print(error_code_string) + except Exception as e: + print(f"解析错误消息失败: {e}") + + return error_code, error_code_string + + +def get_total_tokens(text): + """ + 调用 API 计算给定文本的总 Token 数量。 注:doubao的计算方法!与qianwen不一样 + 返回: + - int: 文本的 total_tokens 数量。 + """ + # API 请求 URL + url = "https://ark.cn-beijing.volces.com/api/v3/tokenization" + + # 获取 API 密钥 + doubao_api_key = os.getenv("DOUBAO_API_KEY") + if not doubao_api_key: + raise ValueError("DOUBAO_API_KEY 环境变量未设置") + + # 请求头 + headers = { + "Content-Type": "application/json", + "Authorization": "Bearer " + doubao_api_key + } + model = "ep-20241119121710-425g6" + # 请求体 + payload = { + "model": model, + "text": [text] # API 文档中要求 text 是一个列表 + } + + try: + response = requests.post(url, headers=headers, json=payload) + response.raise_for_status() + response_data = response.json() + total_tokens=response_data["data"][0]["total_tokens"] + return total_tokens + except Exception as e: + print(f"获取 Token 数量失败:{e}") + return 0 + +def pdf2txt(file_path): + common_header = extract_common_header(file_path) + # print(f"公共抬头:{common_header}") + # print("--------------------正文开始-------------------") + result = "" + with open(file_path, 'rb') as file: + reader = PyPDF2.PdfReader(file) + num_pages = len(reader.pages) + # print(f"Total pages: {num_pages}") + for page_num in range(num_pages): + page = reader.pages[page_num] + text = page.extract_text() + if text: + # print(f"--------第{page_num}页-----------") + cleaned_text = clean_page_content(text,common_header) + # print(cleaned_text) + result += cleaned_text + # print(f"Page {page_num + 1} Content:\n{cleaned_text}") + else: + print(f"Page {page_num + 1} is empty or text could not be extracted.") + directory = os.path.dirname(os.path.abspath(file_path)) + output_path = os.path.join(directory, 'extract.txt') + # 将结果保存到 extract.txt 文件中 + try: + with open(output_path, 'w', encoding='utf-8') as output_file: + output_file.write(result) + print(f"提取内容已保存到: {output_path}") + except IOError as e: + print(f"写入文件时发生错误: {e}") + # 返回保存的文件路径 + return output_path + +def read_txt_to_string(file_path): + """ + 读取txt文件内容并返回一个包含所有内容的字符串,保持原有格式。 + + 参数: + - file_path (str): txt文件的路径 + + 返回: + - str: 包含文件内容的字符串 + """ + try: + with open(file_path, 'r', encoding='utf-8') as file: # 确保使用适当的编码 + content = file.read() # 使用 read() 保持文件格式 + return content + except FileNotFoundError: + return "错误:文件未找到。" + except Exception as e: + return f"错误:读取文件时发生错误。详细信息:{e}" + +def generate_full_user_query(file_path, prompt_template): + """ + 根据文件路径和提示词模板生成完整的user_query。 + + 参数: + - file_path (str): 需要解析的文件路径。 + - prompt_template (str): 包含{full_text}占位符的提示词模板。 + + 返回: + - str: 完整的user_query。 + """ + # 假设extract_text_by_page已经定义,用于提取文件内容 + full_text=read_txt_to_string(file_path) + # 格式化提示词,将提取的文件内容插入到模板中 + user_query = prompt_template.format(full_text=full_text) + return user_query \ No newline at end of file diff --git a/flask_app/general/llm/通义千问long_plus.py b/flask_app/general/llm/通义千问long.py similarity index 65% rename from flask_app/general/llm/通义千问long_plus.py rename to flask_app/general/llm/通义千问long.py index 9756faf..37d8a6c 100644 --- a/flask_app/general/llm/通义千问long_plus.py +++ b/flask_app/general/llm/通义千问long.py @@ -1,15 +1,16 @@ -import ast import json import logging -import re import threading -from functools import wraps from ratelimit import limits, sleep_and_retry import time from pathlib import Path from openai import OpenAI import os +from flask_app.general.llm.大模型通用函数 import get_total_tokens +from flask_app.general.llm.qianwen_turbo import qianwen_turbo +from flask_app.general.llm.大模型通用函数 import extract_error_details, shared_rate_limit + file_write_lock = threading.Lock() @sleep_and_retry @limits(calls=2, period=1) @@ -42,42 +43,6 @@ def upload_file(file_path,output_folder=""): return file_id -@sleep_and_retry -@limits(calls=5, period=1) # 每秒最多调用4次 -def rate_limiter(): - pass # 这个函数本身不执行任何操作,只用于限流 - -# 创建一个共享的装饰器 -def shared_rate_limit(func): - @wraps(func) - def wrapper(*args, **kwargs): - rate_limiter() # 通过共享的限流器 - return func(*args, **kwargs) - return wrapper - -def extract_error_details(error_message): - """ - 从错误消息中提取错误代码和内部错误代码。 - 假设错误消息的格式包含 'Error code: XXX - {...}' - """ - # 提取数值型错误代码 - error_code_match = re.search(r'Error code:\s*(\d+)', error_message) - error_code = int(error_code_match.group(1)) if error_code_match else None - - # 提取内部错误代码字符串(如 'data_inspection_failed') - error_code_string = None - error_dict_match = re.search(r'Error code:\s*\d+\s*-\s*(\{.*\})', error_message) - if error_dict_match: - error_dict_str = error_dict_match.group(1) - try: - # 使用 ast.literal_eval 解析字典字符串 - error_dict = ast.literal_eval(error_dict_str) - error_code_string = error_dict.get('error', {}).get('code') - print(error_code_string) - except Exception as e: - print(f"解析错误消息失败: {e}") - - return error_code, error_code_string @shared_rate_limit def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0, need_extra=False): logger = logging.getLogger('model_log') # 通过日志名字获取记录器 @@ -139,7 +104,7 @@ def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0, need_ex logger.warning(f"错误代码为 400 - {error_code_string},将调用 qianwen_long_stream 执行一次...") try: # 超时就调用 qianwen_long_stream - stream_result = qianwen_long_stream(file_id, user_query, max_retries=0) # 禁用内部重试 + stream_result = qianwen_long_stream(file_id, user_query, max_retries=0,backoff_factor=1,need_extra=need_extra) # 禁用内部重试 if need_extra: if isinstance(stream_result, tuple) and len(stream_result) == 2: return stream_result[0], stream_result[1] # 返回内容和默认的 token_usage=0 @@ -271,116 +236,6 @@ def qianwen_long_stream(file_id, user_query, max_retries=2, backoff_factor=1.0, else: return "" -@sleep_and_retry -@limits(calls=4, period=1) # 每秒最多调用4次 -def qianwen_plus(user_query, need_extra=False): - logger = logging.getLogger('model_log') # 通过日志名字获取记录器 - print("call qianwen-plus...") - - """ - 使用之前上传的文件,根据用户查询生成响应,并实时显示流式输出。 - 目前命中缓存局限:1.不足 256 Token 的内容不会被缓存。 - 2.上下文缓存的命中概率并不是100%,即使是上下文完全一致的请求,也存在无法命中的概率,命中概率依据系统判断而定。 - 3.若多线程同时请求,缓存无法及时更新! - 参数: - - user_query: 用户查询 - - need_extra: 是否需要返回额外数据(默认 False) - 返回: - - 当 need_extra=False 时: 返回响应内容 (str) - - 当 need_extra=True 时: 返回 (响应内容, token_usage) - """ - - # 内部定义重试参数 - max_retries = 2 - backoff_factor = 2.0 - - client = OpenAI( - api_key=os.getenv("DASHSCOPE_API_KEY"), - base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" - ) - - for attempt in range(1, max_retries + 2): # +1 是为了包括初始调用 - try: - completion_tokens = 0 # 初始化 completion_tokens 为 0 - # 生成基于用户查询的响应 - completion = client.chat.completions.create( - model="qwen-plus", - temperature=0.5, - messages=[ - { - 'role': 'user', - 'content': user_query - } - ], - stream=True, # 启用流式响应 - stream_options={"include_usage": True} - ) - - full_response = "" # 用于存储完整的响应内容 - - for chunk in completion: - # 解析 chunk 数据 - if hasattr(chunk, 'to_dict'): - chunk_data = chunk.to_dict() - else: - chunk_data = json.loads(chunk.model_dump_json()) - - # 处理 usage 信息 - usage = chunk_data.get('usage') - if usage is not None: - completion_tokens = usage.get('completion_tokens', 0) - # prompt_tokens_details = usage.get('prompt_tokens_details', {}) #命中tokens ,取消注释可以print - # cache_hit = prompt_tokens_details.get('cached_tokens', 0) - # print("命中:"+str(cache_hit)) - # 处理 choices 信息 - choices = chunk_data.get('choices', []) - if choices: - choice = choices[0] - delta = choice.get('delta', {}) - content = delta.get('content', '') - if content: - full_response += content - # 实时打印内容(可以取消注释下面一行以实时输出) - # print(content, end='', flush=True) - if choice.get('finish_reason'): - # 处理完成原因(如果需要) - pass # 或者记录 finish_reason 以供后续使用 - - if need_extra: - return full_response, completion_tokens - else: - return full_response - - except Exception as exc: - # 提取错误代码 - error_code, error_code_string = extract_error_details(str(exc)) - logger.error(f"第 {attempt} 次尝试失败,查询:'{user_query}',错误:{exc}", exc_info=True) - - if error_code == 429: - if attempt <= max_retries: - sleep_time = backoff_factor * (2 ** (attempt - 1)) # 指数退避 - logger.warning(f"错误代码为 429,将在 {sleep_time} 秒后重试...") - time.sleep(sleep_time) - else: - logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(429 错误)。") - break - else: - # 针对非 429 错误,只重试一次 - if attempt <= 1: - sleep_time = backoff_factor # 固定等待时间 - logger.warning(f"遇到非 429 错误(错误代码:{error_code} - {error_code_string}),将等待 {sleep_time} 秒后重试...") - time.sleep(sleep_time) - continue # 直接跳到下一次循环(即重试一次) - else: - logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败(错误代码:{error_code} - {error_code_string})。") - break - - # 如果所有尝试都失败了,返回空字符串或默认值 - if need_extra: - return "", 0 - else: - return "" - if __name__ == "__main__": # Example file path - replace with your actual file path diff --git a/flask_app/general/商务技术评分提取.py b/flask_app/general/商务技术评分提取.py index 12fbfa4..ee7f260 100644 --- a/flask_app/general/商务技术评分提取.py +++ b/flask_app/general/商务技术评分提取.py @@ -3,12 +3,13 @@ import os import re import time from typing import Any, Dict -from flask_app.general.llm.doubao import read_txt_to_string +from flask_app.general.llm.大模型通用函数 import read_txt_to_string from flask_app.general.file2markdown import convert_file_to_markdown from flask_app.general.format_change import get_pdf_page_count, pdf2docx from flask_app.general.json_utils import extract_content_from_json from flask_app.general.llm.model_continue_query import process_continue_answers -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long, qianwen_plus, qianwen_long_stream +from flask_app.general.llm.通义千问long import upload_file, qianwen_long, qianwen_long_stream +from flask_app.general.llm.qianwen_plus import qianwen_plus def remove_unknown_scores(data): @@ -22,7 +23,11 @@ def remove_unknown_scores(data): return [remove_unknown_scores(item) for item in data] else: return data + def combine_technical_and_business(data): + ''' + 后处理,区分技术评分和商务评分,给外键添加总的评分 + ''' data = remove_unknown_scores(data) extracted_data = { '技术评分': {}, @@ -442,9 +447,9 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type): # 定义用户查询 query = ( - """根据该文档,你判断它是否有关于技术评分或商务评分或投标报价的具体的评分及要求如果有,返回'是',否则返回'否'。 + """根据该文档,你判断它是否有关于技术评分或商务评分或投标报价的具体的评分及要求,如果有,返回'是',否则返回'否'。 要求与指南: - 1. 评分要求主要以表格形式呈现,且有评分因素及评分要求、标准。 + 1. 评分要求主要以表格形式呈现,且有评分因素及评分要求、标准,其中评分因素可以是笼统的评分大项如'技术评分'或'商务评分'。 2. 竞争性磋商文件通常无评分要求,但若满足'1.'的内容,也请返回'是'。 3. 仅返回'是'或'否',不需要其他解释或内容。 """ @@ -551,8 +556,8 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type): if __name__ == "__main__": start_time=time.time() # truncate_file=r"C:\Users\Administrator\Desktop\招标文件-采购类\tmp2\2024-新疆-塔城地区公安局食药环分局快检实验室项目_evaluation_method.pdf" - evaluation_method_path = r'D:\flask_project\flask_app\static\output\output1\test\招标文件-第二章-第六章-172404【电能表标准设备172404-1305001-0002】_evaluation_method.pdf' - invalid_path=r'D:\flask_project\flask_app\static\output\output1\test\招标文件-第二章-第六章-172404【电能表标准设备172404-1305001-0002】_invalid.docx' + evaluation_method_path = r'C:\Users\Administrator\Desktop\货物标\output2\招标文件-通产丽星高端化妆品研发生产总部基地高低压配电工程_evaluation_method11.pdf' + invalid_path=r'C:\Users\Administrator\Desktop\货物标\output2\招标文件-通产丽星高端化妆品研发生产总部基地高低压配电工程_evaluation_method11.pdf' # truncate_file = "C:\\Users\\Administrator\\Desktop\\货物标\\output2\\2-招标文件(统计局智能终端二次招标)_evaluation_method.pdf" # truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output2\\广水市妇幼招标文件最新(W改)_evaluation_method.pdf" # truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\2d481945-1f82-45a5-8e56-7fafea4a7793\\ztbfile_evaluation_method.pdf" diff --git a/flask_app/general/投标人须知正文提取指定内容.py b/flask_app/general/投标人须知正文提取指定内容.py index 1b1bc1c..b295218 100644 --- a/flask_app/general/投标人须知正文提取指定内容.py +++ b/flask_app/general/投标人须知正文提取指定内容.py @@ -3,7 +3,7 @@ import json import re from flask_app.general.json_utils import clean_json_string from flask_app.general.llm.model_continue_query import process_continue_answers -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long_stream +from flask_app.general.llm.通义千问long import upload_file, qianwen_long_stream #提取两个大标题之间的内容 def extract_between_sections(data, target_values,flag=False): diff --git a/flask_app/general/无效标和废标公共代码.py b/flask_app/general/无效标和废标公共代码.py index 576d3e6..e5fc5a3 100644 --- a/flask_app/general/无效标和废标公共代码.py +++ b/flask_app/general/无效标和废标公共代码.py @@ -4,8 +4,8 @@ import re import regex import time from concurrent.futures import ThreadPoolExecutor -from flask_app.general.llm.doubao import generate_full_user_query -from flask_app.general.llm.通义千问long_plus import qianwen_plus +from flask_app.general.llm.大模型通用函数 import generate_full_user_query +from flask_app.general.llm.qianwen_plus import qianwen_plus from flask_app.general.通用功能函数 import process_string_list from collections import OrderedDict from docx import Document diff --git a/flask_app/general/通用功能函数.py b/flask_app/general/通用功能函数.py index 264f47c..2e3cc0f 100644 --- a/flask_app/general/通用功能函数.py +++ b/flask_app/general/通用功能函数.py @@ -1,9 +1,10 @@ # -*- encoding:utf-8 -*- +import json import logging import re from flask_app.general.json_utils import clean_json_string from flask_app.general.llm.多线程提问 import multi_threading -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from flask_app.old_version.判断是否分包等_old import read_questions_from_judge def get_deviation_requirements(invalid_path): @@ -85,10 +86,10 @@ def aggregate_basic_info(baseinfo_list,mode="engineering"): # 定义采购要求的默认值 DEFAULT_PROCUREMENT_REQS = { "采购需求": {}, - "技术要求": [], - "商务要求": [], - "服务要求": [], - "其他要求": [] + "技术要求": ["未提供"], + "商务要求": ["未提供"], + "服务要求": ["未提供"], + "其他要求": ["未提供"] } combined_data = {} relevant_keys_detected = set() diff --git a/flask_app/old_version/不得存在及禁止投标情形_old.py b/flask_app/old_version/不得存在及禁止投标情形_old.py index 933863b..3d23dc2 100644 --- a/flask_app/old_version/不得存在及禁止投标情形_old.py +++ b/flask_app/old_version/不得存在及禁止投标情形_old.py @@ -4,7 +4,7 @@ import re from PyPDF2 import PdfWriter, PdfReader -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from flask_app.general.通用功能函数 import process_string_list diff --git a/flask_app/old_version/判断是否分包等_old.py b/flask_app/old_version/判断是否分包等_old.py index acc04d5..9800f9e 100644 --- a/flask_app/old_version/判断是否分包等_old.py +++ b/flask_app/old_version/判断是否分包等_old.py @@ -5,7 +5,7 @@ import re from flask_app.general.json_utils import extract_content_from_json # 可以选择性地导入特定的函数 from flask_app.old_version.提取打勾符号_old import read_pdf_and_judge_main from flask_app.general.llm.多线程提问 import multi_threading -from flask_app.general.llm.通义千问long_plus import qianwen_long,upload_file +from flask_app.general.llm.通义千问long import qianwen_long,upload_file #调用qianwen-ask之后,组织提示词问百炼。 def construct_judge_questions(json_data): diff --git a/flask_app/old_version/商务评分技术评分整合old_version.py b/flask_app/old_version/商务评分技术评分整合old_version.py index cd80987..cacfcaa 100644 --- a/flask_app/old_version/商务评分技术评分整合old_version.py +++ b/flask_app/old_version/商务评分技术评分整合old_version.py @@ -3,7 +3,7 @@ import json from flask_app.general.json_utils import clean_json_string from flask_app.general.商务技术评分提取 import combine_technical_and_business -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long def combine_evaluation_standards(evaluation_method): # 商务标、技术标评分项:千问 diff --git a/flask_app/old_version/基础信息整合_old.py b/flask_app/old_version/基础信息整合_old.py index 309ee4e..24d386d 100644 --- a/flask_app/old_version/基础信息整合_old.py +++ b/flask_app/old_version/基础信息整合_old.py @@ -4,7 +4,7 @@ from flask_app.general.json_utils import clean_json_string from flask_app.工程标.投标人须知正文提取指定内容工程标 import extract_from_notice from flask_app.old_version.判断是否分包等_old import judge_whether_main, read_questions_from_judge from flask_app.general.llm.多线程提问 import read_questions_from_file, multi_threading -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file from flask_app.general.通用功能函数 import judge_consortium_bidding def aggregate_basic_info_engineering(baseinfo_list): diff --git a/flask_app/old_version/无效标和废标公共代码_old.py b/flask_app/old_version/无效标和废标公共代码_old.py index ec95737..0dc7334 100644 --- a/flask_app/old_version/无效标和废标公共代码_old.py +++ b/flask_app/old_version/无效标和废标公共代码_old.py @@ -4,8 +4,8 @@ import re import regex import time from concurrent.futures import ThreadPoolExecutor -from flask_app.general.llm.doubao import generate_full_user_query -from flask_app.general.llm.通义千问long_plus import qianwen_plus +from flask_app.general.llm.大模型通用函数 import generate_full_user_query +from flask_app.general.llm.qianwen_plus import qianwen_plus from flask_app.general.通用功能函数 import process_string_list from collections import OrderedDict from docx import Document diff --git a/flask_app/old_version/无效标和废标和禁止投标整合_old.py b/flask_app/old_version/无效标和废标和禁止投标整合_old.py index dc9f000..de99ea4 100644 --- a/flask_app/old_version/无效标和废标和禁止投标整合_old.py +++ b/flask_app/old_version/无效标和废标和禁止投标整合_old.py @@ -5,7 +5,7 @@ import time import re from flask_app.general.format_change import pdf2docx -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from concurrent.futures import ThreadPoolExecutor from flask_app.general.table_content_extraction import extract_tables_main diff --git a/flask_app/old_version/评分标准提取main_old.py b/flask_app/old_version/评分标准提取main_old.py index 4193539..0453ffd 100644 --- a/flask_app/old_version/评分标准提取main_old.py +++ b/flask_app/old_version/评分标准提取main_old.py @@ -4,7 +4,7 @@ import time from flask_app.general.json_utils import clean_json_string from flask_app.general.商务技术评分提取 import combine_technical_and_business, \ process_data_based_on_key, reorganize_data -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long def combine_evaluation_standards(truncate_file): # 定义默认的评审结果字典 diff --git a/flask_app/old_version/资格审查模块old_old.py b/flask_app/old_version/资格审查模块old_old.py index e5b43de..efea175 100644 --- a/flask_app/old_version/资格审查模块old_old.py +++ b/flask_app/old_version/资格审查模块old_old.py @@ -4,7 +4,7 @@ from flask_app.old_version.提取json工程标版_old import convert_clause_to_j from flask_app.general.json_utils import extract_content_from_json from flask_app.old_version.形式响应评审old import process_reviews from flask_app.old_version.资格评审old_old import process_qualification -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from concurrent.futures import ThreadPoolExecutor diff --git a/flask_app/old_version/资格评审old_old.py b/flask_app/old_version/资格评审old_old.py index 685272f..dca66d0 100644 --- a/flask_app/old_version/资格评审old_old.py +++ b/flask_app/old_version/资格评审old_old.py @@ -4,7 +4,7 @@ import json import re from flask_app.general.json_utils import clean_json_string, combine_json_results, add_keys_to_json from flask_app.general.llm.多线程提问 import multi_threading, read_questions_from_file -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file def merge_dictionaries_under_common_key(dicts, common_key): diff --git a/flask_app/routes/utils.py b/flask_app/routes/utils.py index 3887139..198960c 100644 --- a/flask_app/routes/utils.py +++ b/flask_app/routes/utils.py @@ -6,7 +6,7 @@ from functools import wraps from flask import request, jsonify, current_app, g from flask_app.general.llm.清除file_id import read_file_ids, delete_file_by_ids -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from flask_app.logger_setup import create_logger diff --git a/flask_app/routes/偏离表数据解析main.py b/flask_app/routes/偏离表数据解析main.py index 94c2bba..cd912c5 100644 --- a/flask_app/routes/偏离表数据解析main.py +++ b/flask_app/routes/偏离表数据解析main.py @@ -7,7 +7,7 @@ from copy import deepcopy from flask_app.general.format_change import docx2pdf,doc2docx from flask_app.general.json_utils import clean_json_string, rename_outer_key from flask_app.general.merge_pdfs import merge_pdfs -from flask_app.general.llm.通义千问long_plus import qianwen_plus +from flask_app.general.llm.qianwen_plus import qianwen_plus from flask_app.general.通用功能函数 import get_global_logger from flask_app.general.截取pdf_main import truncate_pdf_multiple from flask_app.货物标.提取采购需求main import fetch_procurement_reqs diff --git a/flask_app/routes/判断是否是招标文件.py b/flask_app/routes/判断是否是招标文件.py index 5cae9d0..beb17dd 100644 --- a/flask_app/routes/判断是否是招标文件.py +++ b/flask_app/routes/判断是否是招标文件.py @@ -1,7 +1,7 @@ import time from PyPDF2 import PdfReader # 确保已安装 PyPDF2: pip install PyPDF2 -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long def judge_zbfile_exec(file_path): diff --git a/flask_app/routes/小解析main.py b/flask_app/routes/小解析main.py index 9e958e4..f22d037 100644 --- a/flask_app/routes/小解析main.py +++ b/flask_app/routes/小解析main.py @@ -6,7 +6,7 @@ import time from flask_app.general.format_change import docx2pdf from flask_app.general.json_utils import clean_json_string from flask_app.general.llm.多线程提问 import read_questions_from_file, multi_threading -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file from flask_app.general.通用功能函数 import get_global_logger,aggregate_basic_info from flask_app.general.截取pdf_main import truncate_pdf_multiple from flask_app.general.post_processing import inner_post_processing diff --git a/flask_app/test_case/test_doubao.py b/flask_app/test_case/test_doubao.py index 7b12c58..030353e 100644 --- a/flask_app/test_case/test_doubao.py +++ b/flask_app/test_case/test_doubao.py @@ -2,6 +2,7 @@ import concurrent.futures from flask_app.general.llm.doubao import doubao_model +from flask_app.general.llm.qianwen_plus import qianwen_plus # 多线程压力测试 @@ -17,7 +18,7 @@ def multi_threaded_calls_doubao(user_query, num_threads=10): # 定义一个辅助函数来调用 doubao_model 并返回结果 def call_function(thread_id): print(f"线程 {thread_id} 开始调用 doubao_model") - result = doubao_model(user_query) + result = qianwen_plus(user_query) return result # 使用 ThreadPoolExecutor 来管理线程池 diff --git a/flask_app/test_case/test_qianwen_long.py b/flask_app/test_case/test_qianwen_long.py index a7ce4cc..0499c54 100644 --- a/flask_app/test_case/test_qianwen_long.py +++ b/flask_app/test_case/test_qianwen_long.py @@ -1,5 +1,5 @@ import concurrent.futures -from flask_app.general.llm.通义千问long_plus import qianwen_long, upload_file +from flask_app.general.llm.通义千问long import qianwen_long, upload_file def multi_threaded_calls(file_id, user_query, num_threads=1): diff --git a/flask_app/test_case/test_轮询.py b/flask_app/test_case/test_轮询.py new file mode 100644 index 0000000..3b93409 --- /dev/null +++ b/flask_app/test_case/test_轮询.py @@ -0,0 +1,35 @@ +import os +from itertools import cycle +import threading +from concurrent.futures import ThreadPoolExecutor + +# 定义三个 API Key 的循环器 +api_keys = cycle([1, 2, 3]) +# 使用锁保证线程安全 +lock = threading.Lock() + +def test(): + # 使用锁保护对 api_keys 的访问 + with lock: + key = next(api_keys) + print(key) + return key + +def main(): + results = [] + num_calls = 100 # 模拟 100 次并发调用 + # 使用 ThreadPoolExecutor 模拟高并发 + with ThreadPoolExecutor(max_workers=20) as executor: + futures = [executor.submit(test) for _ in range(num_calls)] + # 收集所有返回的结果 + for future in futures: + results.append(future.result()) + + # 统计各个 API Key 被使用的次数 + counts = {1: 0, 2: 0, 3: 0} + for key in results: + counts[key] += 1 + print("调用分布:", counts) + +if __name__ == '__main__': + main() diff --git a/flask_app/工程标/基础信息整合工程标.py b/flask_app/工程标/基础信息整合工程标.py index 6ee2f25..aae4c79 100644 --- a/flask_app/工程标/基础信息整合工程标.py +++ b/flask_app/工程标/基础信息整合工程标.py @@ -7,7 +7,7 @@ from flask_app.general.通用功能函数 import process_judge_questions, aggreg from flask_app.general.投标人须知正文提取指定内容 import extract_from_notice from flask_app.old_version.判断是否分包等_old import merge_json_to_list from flask_app.general.llm.多线程提问 import read_questions_from_file, multi_threading -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file def update_baseinfo_lists(baseinfo_list1, baseinfo_list2): # 创建一个字典,用于存储 baseinfo_list1 中的所有键值对 diff --git a/flask_app/工程标/形式响应评审.py b/flask_app/工程标/形式响应评审.py index 3ee1275..9fe66b8 100644 --- a/flask_app/工程标/形式响应评审.py +++ b/flask_app/工程标/形式响应评审.py @@ -8,7 +8,7 @@ from flask_app.general.llm.多线程提问 import multi_threading from flask_app.工程标.根据条款号整合json import process_and_merge_entries,process_and_merge2 from flask_app.general.json_utils import clean_json_string from flask_app.general.投标人须知正文条款提取成json文件 import convert_clause_to_json -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file from flask_app.general.merge_pdfs import merge_pdfs def update_json_data(original_data, updates1, updates2,second_response_list): """ diff --git a/flask_app/工程标/截取pdf工程标版.py b/flask_app/工程标/截取pdf工程标版.py index a7ae347..28c61ba 100644 --- a/flask_app/工程标/截取pdf工程标版.py +++ b/flask_app/工程标/截取pdf工程标版.py @@ -251,12 +251,12 @@ if __name__ == "__main__": logger = get_global_logger("123") start_time = time.time() # input_path = r"C:\Users\Administrator\Desktop\new招标文件\工程标" - pdf_path=r"C:\Users\Administrator\Desktop\新建文件夹 (3)\新建文件夹\(存储存在问题)惠安县招标文件.pdf" + pdf_path=r"C:\Users\Administrator\Desktop\货物标\zbfiles\招标文件-通产丽星高端化妆品研发生产总部基地高低压配电工程.pdf" # pdf_path = r"C:\Users\Administrator\Desktop\招标文件\招标02.pdf" # input_path=r"C:\Users\Administrator\Desktop\招标文件\招标test文件夹\zbtest8.pdf" - output_folder = r"C:\Users\Administrator\Desktop\新建文件夹 (3)\新建文件夹" - selection = 4 # 例如:1 - 公告 notice , 2 - 评标办法 evaluation_method, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-invalid + output_folder = r"C:\Users\Administrator\Desktop\货物标\output2" + selection = 2 # 例如:1 - 公告 notice , 2 - 评标办法 evaluation_method, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-invalid generated_files = truncate_pdf_main_engineering(pdf_path, output_folder, selection, logger) print(generated_files) # print("生成的文件:", generated_files) diff --git a/flask_app/工程标/资格审查模块main.py b/flask_app/工程标/资格审查模块main.py index ffc9e6b..7576f64 100644 --- a/flask_app/工程标/资格审查模块main.py +++ b/flask_app/工程标/资格审查模块main.py @@ -7,7 +7,7 @@ from flask_app.general.json_utils import extract_content_from_json, clean_json_s from flask_app.general.table_content_extraction import extract_tables_main from flask_app.工程标.形式响应评审 import process_reviews from flask_app.工程标.资格评审 import process_qualification -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from concurrent.futures import ThreadPoolExecutor from flask_app.货物标.资格审查main import combine_qualification_review from flask_app.general.merge_pdfs import merge_pdfs diff --git a/flask_app/工程标/资格评审.py b/flask_app/工程标/资格评审.py index 298699e..19f3b16 100644 --- a/flask_app/工程标/资格评审.py +++ b/flask_app/工程标/资格评审.py @@ -4,7 +4,7 @@ import json import re from flask_app.general.json_utils import clean_json_string, combine_json_results, add_keys_to_json from flask_app.general.llm.多线程提问 import multi_threading, read_questions_from_file -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long # 这个函数的主要用途是将多个相关的字典(都包含 'common_key' 键)合并成一个更大的、综合的字典,所有相关信息都集中在 'common_key' 键下 diff --git a/flask_app/货物标/商务服务其他要求提取.py b/flask_app/货物标/商务服务其他要求提取.py index bfed7e5..66227ab 100644 --- a/flask_app/货物标/商务服务其他要求提取.py +++ b/flask_app/货物标/商务服务其他要求提取.py @@ -4,11 +4,12 @@ import re import fitz from PyPDF2 import PdfReader import textwrap -from flask_app.general.llm.doubao import read_txt_to_string +from flask_app.general.llm.大模型通用函数 import read_txt_to_string from flask_app.general.json_utils import clean_json_string from flask_app.general.llm.model_continue_query import process_continue_answers from flask_app.general.截取pdf通用函数 import create_get_text_function -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long_stream, qianwen_plus +from flask_app.general.llm.通义千问long import upload_file, qianwen_long_stream +from flask_app.general.llm.qianwen_plus import qianwen_plus from flask_app.general.读取文件.clean_pdf import extract_common_header, clean_page_content from flask_app.general.format_change import docx2pdf, pdf2docx import concurrent.futures diff --git a/flask_app/货物标/基础信息解析货物标版.py b/flask_app/货物标/基础信息解析货物标版.py index 7b81e87..2a45132 100644 --- a/flask_app/货物标/基础信息解析货物标版.py +++ b/flask_app/货物标/基础信息解析货物标版.py @@ -6,7 +6,7 @@ import concurrent.futures from flask_app.general.json_utils import clean_json_string, add_outer_key from flask_app.general.通用功能函数 import process_judge_questions, aggregate_basic_info from flask_app.general.llm.多线程提问 import read_questions_from_file, multi_threading -from flask_app.general.llm.通义千问long_plus import upload_file +from flask_app.general.llm.通义千问long import upload_file from flask_app.old_version.判断是否分包等_old import merge_json_to_list from flask_app.general.投标人须知正文提取指定内容 import extract_from_notice from flask_app.货物标.提取采购需求main import fetch_procurement_reqs @@ -60,19 +60,20 @@ def combine_basic_info(merged_baseinfo_path, procurement_path,clause_path,invali # 合并结果 baseinfo_list += temp_list # temp_list 是一个列表 baseinfo_list.append(procurement_reqs) # procurement_reqs 是一个字典 - aggregated_baseinfo = aggregate_basic_info(baseinfo_list,'goods') + aggregated_baseinfo = aggregate_basic_info(baseinfo_list,'goods') #重新组织基础信息结构 return {"基础信息": aggregated_baseinfo} if __name__ == "__main__": start_time=time.time() # baseinfo_file_path = "C:\\Users\\Administrator\\Desktop\\货物标\\truncate_all\\ztbfile_merged_baseinfo\\ztbfile_merged_baseinfo_3-31.pdf" - merged_baseinfo_path=r"C:\Users\Administrator\Desktop\fsdownload\0c80edcc-cc86-4d53-8bd4-78a531446760\ztbfile.docx" + merged_baseinfo_path=r"D:\flask_project\flask_app\static\output\output1\ecd3374a-a19e-475e-a4dd-e803a3bc1fbf\ztbfile_merged_baseinfo.pdf" # procurement_file_path = "C:\\Users\\Administrator\\Desktop\\fsdownload\\b4601ea1-f087-4fa2-88ae-336ad4d8e1e9\\tmp\\ztbfile_procurement.pdf" - clause_path=r'D:\flask_project\flask_app\static\output\output1\3783ce68-1839-4449-97e6-cd07749d8664\clause1.json' - invalid_path=r"C:\Users\Administrator\Desktop\fsdownload\0c80edcc-cc86-4d53-8bd4-78a531446760\ztbfile.docx" + clause_path=r'D:\flask_project\flask_app\static\output\output1\ecd3374a-a19e-475e-a4dd-e803a3bc1fbf\clause1.json' + invalid_path=r"D:\flask_project\flask_app\static\output\output1\ecd3374a-a19e-475e-a4dd-e803a3bc1fbf\ztbfile.docx" + procurement_path=r'D:\flask_project\flask_app\static\output\output1\ecd3374a-a19e-475e-a4dd-e803a3bc1fbf\ztbfile_procurement.pdf' # res = combine_basic_info(merged_baseinfo_path, procurement_file_path,clause_path) - res=combine_basic_info(merged_baseinfo_path,"","",invalid_path) + res=combine_basic_info(merged_baseinfo_path,procurement_path,clause_path,invalid_path) print("------------------------------------") print(json.dumps(res, ensure_ascii=False, indent=4)) end_time=time.time() diff --git a/flask_app/货物标/截取pdf货物标版.py b/flask_app/货物标/截取pdf货物标版.py index f506e9e..67e2109 100644 --- a/flask_app/货物标/截取pdf货物标版.py +++ b/flask_app/货物标/截取pdf货物标版.py @@ -319,11 +319,11 @@ if __name__ == "__main__": logger = get_global_logger("123") # input_path = r"C:\Users\Administrator\Desktop\new招标文件\货物标" # pdf_path = r"C:\Users\Administrator\Desktop\招标文件-采购类\2024-贵州-贵州医科大学附属医院导视系统零星制作安装项目.pdf" - pdf_path=r"C:\Users\Administrator\Desktop\货物标\zbfiles\招标文件(107国道).pdf" + pdf_path=r"C:\Users\Administrator\Desktop\货物标\zbfiles\file1737339029349.pdf" # input_path = r"C:\Users\Administrator\Desktop\货物标\zbfiles\2-招标文件(广水市教育局封闭管理).pdf" # pdf_path=r"C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\1414cb9c-7bf4-401c-8761-2acde151b9c2\ztbfile.pdf" - output_folder = r"C:\Users\Administrator\Desktop\货物标\zbfiles\output6" + output_folder = r"C:\Users\Administrator\Desktop\货物标\output2" # output_folder = r"C:\Users\Administrator\Desktop\new招标文件\output2" - selection = 6 # 例如:1 - 公告 notice , 2 - 评标办法 evaluation_method, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求 procurement 6-invalid + selection = 2 # 例如:1 - 公告 notice , 2 - 评标办法 evaluation_method, 3 - 资格审查后缀有qualification1或qualification2(与评标办法一致) 4.投标人须知前附表part1 投标人须知正文part2 5-采购需求 procurement 6-invalid generated_files = truncate_pdf_main_goods(pdf_path, output_folder, selection,logger) print(generated_files) diff --git a/flask_app/货物标/技术参数要求提取.py b/flask_app/货物标/技术参数要求提取.py index abe92e7..4933eb4 100644 --- a/flask_app/货物标/技术参数要求提取.py +++ b/flask_app/货物标/技术参数要求提取.py @@ -8,9 +8,10 @@ from copy import deepcopy from flask_app.general.llm.model_continue_query import process_continue_answers from flask_app.general.format_change import pdf2docx from flask_app.general.llm.多线程提问 import multi_threading -from flask_app.general.llm.通义千问long_plus import qianwen_long, upload_file, qianwen_plus +from flask_app.general.llm.通义千问long import qianwen_long, upload_file +from flask_app.general.llm.qianwen_plus import qianwen_plus from flask_app.general.json_utils import clean_json_string -from flask_app.general.llm.doubao import read_txt_to_string +from flask_app.general.llm.大模型通用函数 import read_txt_to_string from flask_app.货物标.技术参数要求提取后处理函数 import main_postprocess diff --git a/flask_app/货物标/资格审查main.py b/flask_app/货物标/资格审查main.py index d120d4c..35fd101 100644 --- a/flask_app/货物标/资格审查main.py +++ b/flask_app/货物标/资格审查main.py @@ -3,7 +3,7 @@ import json import re import time from concurrent.futures import ThreadPoolExecutor, as_completed -from flask_app.general.llm.通义千问long_plus import upload_file, qianwen_long +from flask_app.general.llm.通义千问long import upload_file, qianwen_long from flask_app.general.json_utils import clean_json_string