项目地址：[zy123/zbparse - zbparse - 智标领航代码仓库](http://47.98.59.178:3000/zy123/zbparse)

git clone地址：http://47.98.59.178:3000/zy123/zbparse.git

选择develop分支，develop-xx 后面的xx越近越新。

正式环境：121.41.119.164:5000

测试环境：47.98.58.178:5000

大解析：指从招标文件解析入口进去，upload.py 

小解析：从投标文件生成入口进去，little_zbparse 和get_deviation，两个接口后端一起调

## 项目结构：

![1](md_files/1.png)

.env存放一些密钥（大模型、textin等），它是gitignore忽略了，因此在服务器上git pull项目的时候，这个文件不会更新（因为密钥比较重要），需要手动维护服务器相应位置的.env。

**如何更新服务器上的版本：**

1. 进入项目文件夹

![1](md_files/0.png)

**注意：**需要确认.env是否存在在服务器，默认是隐藏的
输入cat .env
如果不存在，在项目文件夹下sudo vim .env

将密钥粘贴进去！！！

2. git pull 

3. sudo docker-compose up --build -d 更新并重启

​	或者	sudo docker-compose build  先构建镜像

​				sudo docker-compose up -d	等空间时再重启

4. sudo docker-compose logs flask_app --since 1h 查看最近1h的日志（如果重启后报错也能查看，推荐重启后都运行一下这个）



requirements.txt一般无需变动，除非代码中使用了新的库，也要手动在该文件中添加包名及对应的版本



**如何本地启动本项目：**

1. requirements.txt里的环境要配好
2. .env环境配好 （一般不需要在电脑环境变量中额外配置了）

3. 点击下拉框，Edit configurations

 ![1](md_files/11.png)

​	设置run_serve.py为启动脚本![1](md_files/10.png)

4. postman打post请求测试：

http://127.0.0.1:5000/upload

body:

{

  "file_url":"xxxx",

  "zb_type":2

}



## flask_app结构介绍

### general

是公共函数存放的文件夹，llm下是各类大模型，读取文件下是docx pdf文件的读取以及文档清理clean_pdf，去页眉页脚页码

![1](md_files/2.png)

general下的llm下的清除file_id.py 需要**每周运行至少一次**，防止file_id数量超出（我这边对每次请求结束都有file_id记录并清理，向应该还没加）

llm下的model_continue_query是'模型继续回答'脚本，应对超长文本模型一次无法输出完的情况，继续提问，拼接成完整的内容。



general下的file2markdown是textin 文件--》markdown

general下的format_change是pdf-》docx 或doc/docx->pdf

general下的merge_pdfs.py是拼接文件的：1.拼接招标公告+投标人须知   2.拼接评标细则章节+资格审查章节



**general中比较重要的！！！**

**后处理：**

general下的**post_processing**,解析后的后处理部分，包括extract_info、 资格审查、技术偏离 商务偏离 所需提交的证明材料，都在这块生成。

post_processing中的**inner_post_processing**专门提取*extracted_info*

post_processing中的**process_functions_in_parallel**提取

资格审查、技术偏离、 商务偏离、 所需提交的证明材料

![1](md_files/14.png)

大解析upload用了post_processing完整版，

little_zbparse.py、小解析main.py用了inner_post_processing

get_deviation.py、偏离表数据解析main.py用了process_functions_in_parallel



**截取pdf：**

*截取pdf_main.py*是顶级函数，

二级是*截取pdf货物标版*.py和*截取pdf工程标版.py*  （非general下）

三级是*截取pdf通用函数.py*

如何判断截取位置是否正确？根据output文件夹中的切分情况（打开各个文件查看是否切分准确，目前的逻辑主要是按大章切分，即'招标公告'章节）



**如果切分不准确，如何定位正则表达式？**

首先判断当前是工程标解析还是货物标解析，即zb_type=1还是2

如果是2，那么是货物标解析，那么就是*截取pdf_main.py*调用*截取pdf货物标版*.py，如下图，selection=1代表截取'招标公告'，那么如果招标公告没有切准，就在这块修改。这里可以发现get_notice是通用函数，即*截取pdf通用函数.py*中的get_notice函数，那么继续往内部跳转。

若开头没截准，就改begin_pattern，末尾没截准，就改end_pattern

![1](md_files/18.png)

![1](md_files/19.png)

另外：在*截取pdf货物标版*.py中，还有extract_pages_twice函数，即第一次没有切分到之后，会运行该函数，这边又有一套begin_pattern和end_pattern，即二次提取



**如何测试？**

![1](md_files/20.png)

输入pdf_path，和你要切分的序号，selection=1代表切公告，依次类推，可以看切出来的效果如何。



**无效标和废标公共代码**

获取无效标与废标项的主要执行代码。对docx文件进行预处理=》正则=》temp.txt=》大模型筛选
如果提的不全，可能是正则没涵盖到位，也可能是大模型提示词漏选了。

这里：如果段落中既被正则匹配，又被follow_up_keywords中的任意一个匹配，那么不会添加到temp中（即不会被大模型筛选），它会**直接添加**到最后的返回中!

![1](md_files/12.png)



**投标人须知正文条款提取成json文件**

将截取到的ztbfile_tobidders_notice_part2.pdf ，即须知正文，转为clause1.json 文件，便于后续提取**开评定标流程**、**投标文件要求**、**重新招标、不再招标和终止招标**

这块的主要逻辑就是匹配形如'一、总则'这样的大章节

然后匹配形如'1.1' '1.1.1'这样的序号，由于是按行读取pdf，一个序号后面的内容可能有好几行，因此遇到下一个序号（如'2.1')开头，之前的内容都视为上一个序号的。



### old_version

都是废弃文件代码，未在正式、测试环境中使用的，不用管

![1](md_files/3.png)



### routes

是接口以及主要实现部分，一一对应

![1](md_files/4.png)

get_deviation对应偏离表数据解析main，获得偏离表数据

judge_zbfile对应判断是否是招标文件

little_zbparse对应小解析main，负责解析extract_info

test_zbparse是测试接口，无对应

upload对应工程标解析和货物标解析，即大解析

**混淆澄清**：小解析可以指代一个过程，即从'投标文件生成'这个入口进去的解析，后端会同时调用little_zbparse和get_deviation。这个过程称为'小解析'。

但是little_zbparse也叫小解析，命名如此因为最初只需返回这些数据(extract_info)，后续才陆续返回商务、技术偏离...



utils是接口这块的公共功能函数。其中validate_and_setup_logger函数对不同的接口请求对应到不同的output文件夹，如upload->output1。后续增加接口也可直接在这里写映射关系。

![1](md_files/5.png)

重点关注大解析：**upload.py**和**货物标解析main.py**



### static

存放解析的输出和提示词

其中output用gitignore了，git push不会推送这块内容。

各个文件夹(output1 output2..)对应不同的接口请求

![1](md_files/6.png)



### test_case&testdir

test_case是测试用例，是对一些函数的测试。好久没更新了

testdir是平时写代码的测试的地方

它们都不影响正式和测试环境的解析

![1](md_files/7.png)



### 工程标&货物标

是两个解析流程中不一样的地方（一样的都写在**general**中了）

![1](md_files/8.png)

主要是货物标额外解析了采购要求（提取采购需求main+技术参数要求提取+商务服务其他要求提取）



### 最后：

ConnectionLimiter.py定义了接口超时时间->超时后断开与后端的连接

![1](md_files/9.png)

logger_setup.py 为每个请求创建单独的log，每个log对应一个log.txt

start_up.py是启动脚本，run_serve也是启动脚本，是对start_up.py的简单封装，目前dockerfile定义的直接使用run_serve启动



## 持续关注

```
 yield sse_format(tech_deviation_response)
 yield sse_format(tech_deviation_star_response)
 yield sse_format(zigefuhe_deviation_response)
 yield sse_format(shangwu_deviation_response)
 yield sse_format(shangwu_star_deviation_response)
 yield sse_format(proof_materials_response)
```

1. 工程标解析目前仍没有解析采购要求这一块，因此后处理返回的只有'资格审查'和''证明材料"和"extracted_info"，没有''商务偏离''及'商务带星偏离'，也没有'技术偏离'和'技术带星偏离'，而货物标解析是完全版。

​	其中''证明材料"和"extracted_info"是直接返给后端保存的

2. 大解析中返回了技术评分，后端接收后不仅显示给前端，还会返给向，用于生成技术偏离表
3. 小解析时，get_deviation.py其实也可以返回技术评分，但是没有返回，因为没人和我对接，暂时注释了。

![1](md_files/16.png)



4.商务评议和技术评议偏离表，即评分细则的偏离表，暂时没做，但是**商务评分、技术评分**无论大解析还是小解析都解析了，稍微对该数据处理一下返回给后端就行。

![1](md_files/17.png)

这个是解析得来的结果，适合给前端展示，但是要生成商务技术评议偏离表的话，需要再调一次大模型，对该数据进行重新归纳，以字符串列表为佳。再传给后端。（未做）