AITDBManger开发指导
# 1 开发规范
警告
禁止在master分支进行开发!
# 1.1 克隆代码仓库到本地
提示
仅有首次参与开发的同学需要进行这个操作
在个人PC安装好Git,新建空文件夹,用于存储项目代码,在空文件夹内右键鼠标,选择Git Bash Here,打开Git命令行窗口。
在命令行窗口执行
git clone http://172.16.111.6:10080/AIT/BaseInfrastructure/AITDBManager.git
# 1.2 更新master分支代码
提示
刚刚完成克隆代码仓库的同学不需要这个操作;
其他情况需要先更新master分支代码;
cd AITDBManager
git checkout master
git pull
2
3
命令行窗口显示如下信息则说明已更新为最新代码。
Administrator@Evi1-PC MINGW64 /e/doc_demo/AITDBManager (master)
$ git pull
Already up to date.
2
3
# 1.3 创建开发分支
注意
分支命名要有意义;
分支命名要使用英文。
举个例子,我要新增一种身份证识别用途的标注数据,其分支名称可以命名为add_qr_code_recognition_image
git checkout -b add_qr_code_recognition_image
执行成功的效果如下所示,可以看到命令行窗口的分支提示已经变为新创建的分支。
Administrator@Evi1-PC MINGW64 /e/doc_demo/AITDBManager (master)
$ git checkout -b add_qr_code_recognition_image
Switched to a new branch 'add_qr_code_recognition_image'
Administrator@Evi1-PC MINGW64 /e/doc_demo/AITDBManager (add_qr_code_recognition_image)
$
2
3
4
5
6
接下来可以在新分支上进行代码开发。记得及时提交代码到GitLab,避免代码丢失。
# 1.4 完成开发后提交合并请求
完成开发的定义是什么?
服务端AITDBManager和客户端AITDBClient均完成开发,自测通过。
提示
分支合并请求在GitLab项目仓库的版本库->分支菜单下,对需要合并的分支进行操作。
开发完成,测试通过后,通过GitLab创建分支合并请求,待项目管理员代码审查通过后合入主干分支。
# 2 概述
提示
- 使用Python3.7.7版本进行开发和运行;
- 使用PypiManager (opens new window)作为pip源;
- 强烈建议使用
virtualenv创建虚拟环境进行开发和运行
服务端开发基于Python 3.7.7版本,使用到第三方库主要如下:
- SQLAlchemy,使用广泛的
ORM组件,提供对关系型数据库的对象操作能力; - Alembic,与SQLAlchemy配套使用的数据库迁移工具,提供对数据库的“版本管理”能力;
- FastAPI,高效易用,自带API文档的Web开发框架,提供各种
API的开发的能力;
除Python外,服务端使用到的服务组件主要有MySQL5.7、MinIO。
# 2.1 项目结构

对于开发人员来说,需要关注的主要内容为以下内容
点击查看
.
├── alembic.ini
├── api
│ ├── base.py
│ ├── cruds 【定义新增标注数据的数据库操作逻辑】
│ ├── __init__.py
│ ├── routers 【定义新增标注数据的路由地址】
│ ├── schemas 【定义新增标注数据请求体结构】
│ ├── server.py 【注册新增标注数据的路由方法】
│ └── static
├── docker-compose.yaml
├── docs
├── manager.py
├── migrations
├── models
│ ├── base_enum.py
│ ├── __init__.py
│ ├── model_common.py
│ ├── sys_enum.py
│ ├── sys_model.py
│ ├── user_define_enum.py 【可选:增加标注数据对应的model字段枚举类型,用于声明枚举类型】
│ └── user_define_model.py 【增加标注数据对应的数据库model,定义表结构,用于MySQL的CRUD操作】
├── mysql
├── README.md
├── requirements.txt
├── settings.py
├── setup.sh
└── utils
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 3 开发要点
警告
禁止在master分支进行开发!
情景提示,下文均以此情景展开
我们以二维码识别的图片标注数据为例进行讲解,已知每一张二维码识别图片的标注信息主要有如下内容:
- 二维码的坐标(数组类型,4个点,8个整型数字)
- 二维码所编码的文本信息(字符串,长度可能会比较大,比如一些URL地址)
- 是否为核心测试场景(字符串)
# 3.1 定义数据库model
为了能在数据库存储上文描述的图片二维码识别标注数据,我们需要先定义一张表来存储这些信息。
在models包的user_define_model.py文件中,新增如下代码:
点击查看
class AnnImageQRCodeRecognition(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-二维码识别信息
"""
__tablename__ = 'ann_image_qrcode_recognition'
__table_args_map__ = {
'comment': '图片标注-二维码识别信息'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation = Column(MEDIUMTEXT, nullable=False, comment='二维码对应标注内容')
is_core_scene = Column(String(length=32), nullable=False, comment='二维码是否属于核心场景')
2
3
4
5
6
7
8
9
10
11
12
13
下面解读下这段代码的含义以及相关规范
# 3.1.1 model类名规范
标注数据的的model类名分为3段信息:Ann{FileType}{AnnotationDataType}
- 统一以
Ann开头, - 根据测试样本文件实体类型进行区分:
Image、Audio、Video - 最后是标注数据具体类别
model类统一继承自CommonTableArgsMixin, CommonColumnMixin, Base。
其中CommonTableArgsMixin提供了对表参数的公共属性封装和参数支持;CommonColumnMixin包含了对公共字段的封装,可以简化代码。
class AnnImageQRCodeRecognition(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-二维码识别信息
"""
__tablename__ = 'ann_image_qrcode_recognition'
__table_args_map__ = {
'comment': '图片标注-二维码识别信息'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation = Column(MEDIUMTEXT, nullable=False, comment='二维码对应标注内容')
is_core_scene = Column(String(length=32), nullable=False, comment='二维码是否属于核心场景')
2
3
4
5
6
7
8
9
10
11
12
13
# 3.1.2 model注释规范
根据测试样本实体类型,标注信息类别进行注释:
- 图片标注-XXXX
- 视频标注-XXXX
- 音频标注-XXXX
class AnnImageQRCodeRecognition(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-二维码识别信息
"""
__tablename__ = 'ann_image_qrcode_recognition'
__table_args_map__ = {
'comment': '图片标注-二维码识别信息'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation = Column(MEDIUMTEXT, nullable=False, comment='二维码对应标注内容')
is_core_scene = Column(String(length=32), nullable=False, comment='二维码是否属于核心场景')
2
3
4
5
6
7
8
9
10
11
12
13
# 3.1.3 model的table参数规范
必须要填写的字段为__tablename__、__table_args_map__,可选字段为__table_args_array__。
__tablename__为数据库表名称,统一小写,下划线分隔,即对驼峰命名的model类名改为下划线分隔的小写表名;__table_args_map__为字典参数,需要填写其comment值为model的注释,此字段用于在数据库中声明表名注释__table_args_array__为列表参数,一般用于声明联合索引,通常用不到,使用示例__table_args_array__ = [UniqueConstraint('category', 'cn_name', 'en_name', name='uk_ds')]
class AnnImageQRCodeRecognition(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-二维码识别信息
"""
__tablename__ = 'ann_image_qrcode_recognition'
__table_args_map__ = {
'comment': '图片标注-二维码识别信息'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation = Column(MEDIUMTEXT, nullable=False, comment='二维码对应标注内容')
is_core_scene = Column(String(length=32), nullable=False, comment='二维码是否属于核心场景')
2
3
4
5
6
7
8
9
10
11
12
13
# 3.1.4 model的字段规范
字段按照作用通常可以分为2类,
- 根据测试样本实体文件类型,有文件md5值的一个唯一索引字段,保证标注数据的唯一性,其为元数据表的外键;
- 标注数据的描述信息。
md5唯一索引字段根据测试样本实体文件文件类型有如下3种:
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')audio = Column(String(length=32), ForeignKey('audio_meta.md5'), unique=True, nullable=False, comment='音频文件md5')video = Column(String(length=32), ForeignKey('video_meta.md5'), unique=True, nullable=False, comment='视频文件md5值')
其他字段就是对应的标注数据信息了,通常遵循如下字段类型:
JSON:用于定义坐标信息,或者不便于逐个字段定义的非常复杂的标注信息;MEDIUMTEXT:用于定义长度很大的字符串,最长可支持16MB大小的字符串;String:通常用于定义普通长度的字符串,根据实际情况定义字段长度,比如姓名字段其长度可以定义为String(length=4),其长队最大为65532个字节;Integer:用于定义整型数字信息;Float:用于定义浮点型数字信息;Enum:用于定义枚举类型信息,通常还会设定默认值,但使用枚举类型必须先在user_define_enum.py文件定义。
# 3.1.4.1 Enum类型定义
枚举类型定义及使用示例
# 在user_define_enum.py定义枚举类型
class OCRComposing(str, Enum):
"""图片标注-OCR信息-文字排版类别"""
horizontal = '水平排版'
vertical = '竖直排版'
hybrid = '混合排版'
unmark = '未标注排版类别'
# 在user_define_model.py使用定义的枚举类型
class AnnImageUniversalOCR(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-通用OCR信息表
"""
__tablename__ = 'ann_image_universal_ocr'
__table_args_map__ = {
'comment': '图片标注-通用OCR信息表'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation_array = Column(JSON, nullable=False, comment='标注文本信息数组')
box_composing_array = Column(JSON, nullable=False, comment='标注框布局类别数组')
composing = Column(Enum(OCRComposing), nullable=False, default=OCRComposing.unmark, comment='图片文字排版类别')
sensibility = Column(Enum(OCRSensibility), nullable=False, default=OCRSensibility.unmark, comment='内容敏感类别')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class AnnImageQRCodeRecognition(CommonTableArgsMixin, CommonColumnMixin, Base):
"""
图片标注-二维码识别信息
"""
__tablename__ = 'ann_image_qrcode_recognition'
__table_args_map__ = {
'comment': '图片标注-二维码识别信息'
}
image = Column(String(length=32), ForeignKey('image_meta.md5'), unique=True, nullable=False, comment='图片文件md5值')
coordinates_array = Column(JSON, nullable=False, comment='标注框坐标数组')
annotation = Column(MEDIUMTEXT, nullable=False, comment='二维码对应标注内容')
is_core_scene = Column(String(length=32), nullable=False, comment='二维码是否属于核心场景')
2
3
4
5
6
7
8
9
10
11
12
13
# 3.2 定义API请求体结构
在api/schemas目录下新建ann_image_qrcode_recognition.py文件,用于定义图片标注-二维码识别信息的API数据校验和字段映射逻辑。
新建3个类,数据校验基础定义根据model的表字段名称和类型来定义,注意注释要正确。
AnnImageQRCodeRecognitionBaseAnnImageQRCodeRecognitionCreateAnnImageQRCodeRecognition
示例代码
class AnnImageQRCodeRecognitionBase(BaseModel, extra=Extra.forbid):
"""图片标注-二维码识别信息API数据校验基础定义"""
image: str = Field(..., description='图片文件md5值')
coordinates_array: List[List[int]] = Field(..., description='标注框坐标数组')
annotation: str = Field(..., description='二维码对应标注内容')
is_core_scene: str = Field(..., description='二维码是否属于核心场景')
remark: Optional[str] = Field(None, description='备注信息')
status: Optional[DeleteStatusEnum] = Field(DeleteStatusEnum.not_delete, description='是否被逻辑删除')
class AnnImageQRCodeRecognitionCreate(AnnImageQRCodeRecognitionBase):
"""图片标注-二维码识别信息API数据校验基础定义-新增数据"""
class AnnImageQRCodeRecognition(AnnImageQRCodeRecognitionBase):
"""图片标注-二维码识别信息API数据校验基础定义-数据读取和响应体"""
create_time: Optional[datetime] = None
update_time: Optional[datetime] = None
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3.3 定义API数据库操作逻辑
在api/cruds目录下新增ann_image_qrcode_recognition.py文件,用于定义图片标注-二维码识别信息的API对数据库的增删改查逻辑。
要点:
- 导入在
schemas中定义的AnnImageQRCodeRecognitionCreate类; - 新建数据入库方法
create_ann_image_qrcode_recognition,注意修改注释;
示例代码
from AITUtils.log import logger
import models.user_define_model as model
from api.schemas.base_schema import ResponseBase
from api.schemas.ann_image_qrcode_recognition import AnnImageQRCodeRecognitionCreate
from api.base import DB
from utils.error_code import error_code
@logger.catch(reraise=True)
def create_ann_image_qrcode_recognition(db: DB, ann_image_qrcode_recognition: AnnImageQRCodeRecognitionCreate):
"""新增图片标注-二维码识别信息"""
description = create_ann_image_qrcode_recognition.__doc__.strip()
try:
db.insert_or_update(model.AnnImageQRCodeRecognition, **ann_image_qrcode_recognition.dict())
resp_data = ResponseBase(description=description).dict()
except Exception as err:
status = error_code.DB_INSERT_OR_UPDATE_ERROR.get('code')
message = f'''{error_code.DB_INSERT_OR_UPDATE_ERROR.get('description')}: {str(err)}'''
resp_data = ResponseBase(description=description,
status=status,
message=message).dict()
else:
db.session.commit()
return resp_data
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 3.4 定义API路由
在api/routers目录下新增ann_image_qrcode_recognition.py文件,用于定义图片标注-二维码识别信息的API路由地址和请求体结构。
要点:
- 导入在
schemas中定义的AnnImageQRCodeRecognitionCreate类; - 导入在
cruds中定义的ann_image_qrcode_recognition方法; - 新建数据API操作方法
create_ann_image_qrcode_recognition,注意修改注释;
示例代码
from fastapi import Depends
import api.cruds.ann_image_qrcode_recognition as crud
from api.schemas.base_schema import ResponseBase
from api.schemas.ann_image_qrcode_recognition import AnnImageQRCodeRecognitionCreate
from api.base import DB, get_db, router
@router.post('/ann_image_qrcode_recognition', response_model=ResponseBase)
def create_ann_image_qrcode_recognition(ann_image_qrcode_recognition_data: AnnImageQRCodeRecognitionCreate,
db: DB = Depends(get_db)):
"""新增图片标注-二维码识别信息"""
return crud.create_ann_image_qrcode_recognition(db=db,
ann_image_qrcode_recognition=ann_image_qrcode_recognition_data)
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.5 注册API路由
修改api/server.py文件,导入在api/routers定义的图片标注-二维码识别的路由ann_image_qrcode_recognition,并进行路由注册。
示例代码
from api.routers import dynamic_query
from api.routers import equipment_info
from api.routers import data_source_info
from api.routers import system_dict
from api.routers import oss_info
from api.routers import identity_info
from api.routers import audio_meta
from api.routers import image_meta
from api.routers import video_meta
from api.routers import ann_image_qrcode_recognition
app.include_router(dynamic_query.router)
app.include_router(equipment_info.router)
app.include_router(data_source_info.router)
app.include_router(system_dict.router)
app.include_router(oss_info.router)
app.include_router(identity_info.router)
app.include_router(audio_meta.router)
app.include_router(image_meta.router)
app.include_router(video_meta.router)
app.include_router(ann_image_qrcode_recognition.router)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 3.6 更新数据库表结构
在项目根目录打开命令行窗口执行如下命令,
警告
命令中的MSG,应为本次开发新增的或修改的数据库表model内容;
必须用英文书写;
举个例子,本示例场景可以写为alembic revision --autogenerate -m "add ann_image_qrcode_recognition"
alembic revision --autogenerate -m "MSG"
alembic upgrade head
2
# 3.7 本地启动API服务条数自测
# 3.7.1 启动本地API服务
在本地允许manager.py,服务可以正常启动且无报错:
O:\GITLAB\AIT\BaseInfrastructure\AITDBManager\venv\Scripts\python.exe O:/GITLAB/AIT/BaseInfrastructure/AITDBManager/manager.py
2021-11-12 15:15:38 | INFO | manager __create_bucket__:75 - 无需创建Minio存储桶
2021-11-12 15:15:38 | INFO | manager __load_sys_dict__:110 - 共计69个字典码
2021-11-12 15:15:39 | INFO | server serve:64 - Started server process [12040]
2021-11-12 15:15:39 | INFO | on startup:26 - Waiting for application startup.
2021-11-12 15:15:39 | INFO | on startup:38 - Application startup complete.
2021-11-12 15:15:39 | INFO | server _log_started_message:204 - Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
2
3
4
5
6
7
# 3.7.2 访问本地API Doc
Chrome浏览器打开 http://127.0.0.1:5000/docs ,确认新增的图片标注-二维码识别API接口成功。
