项目初次提交

This commit is contained in:
2025-04-11 08:54:28 +08:00
commit 9e14a3256f
220 changed files with 15673 additions and 0 deletions

View File

View File

@ -0,0 +1,156 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:25
# @File : crud.py
# @IDE : PyCharm
# @desc : 数据访问层
import application.settings
from . import schemas, models, params
from apps.vadmin.auth.utils.validation.auth import Auth
from utils import os_utils as os, random_utils as ru
if application.settings.DEBUG:
from application.config.development import datasets_url, runs_url, detect_url, yolo_url, images_url
else:
from application.config.production import datasets_url, runs_url, detect_url, yolo_url, images_url
from typing import Any, List
from core.crud import DalBase
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, case, and_
class ProjectInfoDal(DalBase):
def __init__(self, db: AsyncSession):
super(ProjectInfoDal, self).__init__()
self.db = db
self.model = models.ProjectInfo
self.schema = schemas.ProjectInfoOut
async def get_project_pager(self, project: params.ProjectInfoParams, auth: Auth):
"""
分页查询项目列表
"""
# 定义子查询
subquery = (
select(
models.ProjectImage.project_id,
func.sum(case((models.ProjectImgLeafer.id.is_(None), 1), else_=0)).label('no_mark_count'),
func.sum(case((models.ProjectImgLeafer.id.isnot(None), 1), else_=0)).label('mark_count')
)
.outerjoin(models.ProjectImgLeafer, models.ProjectImage.id == models.ProjectImgLeafer.image_id)
.group_by(models.ProjectImage.project_id)
.subquery()
)
full_query = select(
models.ProjectInfo,
func.ifnull(subquery.c.mark_count, 0).label("mark_count"),
func.ifnull(subquery.c.no_mark_count, 0).label("no_mark_count")
).select_from(models.ProjectInfo).join(
subquery, models.ProjectInfo.id == subquery.c.project_id, isouter=True
)
v_where = [models.ProjectInfo.is_delete.is_(False)]
if '*' in auth.dept_ids:
v_where.append(models.ProjectInfo.dept_id.isnot(None))
else:
v_where.append(models.ProjectInfo.dept_id.in_(auth.dept_ids))
sql = await self.filter_core(
v_start_sql=full_query,
v_where=v_where,
v_return_sql=True,
v_order=project.v_order,
v_order_field=project.v_order_field
)
count = await self.get_count_sql(sql)
if project.limit != 0:
sql = sql.offset((project.page - 1) * project.limit).limit(project.limit)
queryset = await self.db.execute(sql)
result = queryset.all()
datas = []
for result in result:
data = schemas.ProjectInfoPagerOut.model_validate(result[0])
data.mark_count = int(result[1])
data.no_mark_count = int(result[2])
datas.append(data.model_dump())
return datas, count
async def check_name(self, project_name: str):
"""
校验项目名称是否重名
"""
count = await self.get_count(v_where=[models.ProjectInfo.project_name == project_name,
models.ProjectInfo.is_delete is False])
return count > 0
async def add_project(
self,
project: schemas.ProjectInfoIn,
auth: Auth
) -> Any:
obj = self.model(**project.model_dump())
obj.user_id = auth.user.id
obj.project_no = ru.random_str(6)
obj.project_status = "0"
obj.train_version = 0
obj.user_id = auth.user.id
if '*' in auth.dept_ids:
obj.dept_id = 0
else:
obj.dept_id = auth.dept_ids[0]
os.create_folder(datasets_url, obj.project_no)
os.create_folder(runs_url, obj.project_no)
await self.flush(obj)
return await self.out_dict(obj, None, False, schemas.ProjectInfoOut)
class ProjectImageDal(DalBase):
def __init__(self, db: AsyncSession):
super(ProjectImageDal, self).__init__()
self.db = db
self.model = models.ProjectImage
self.schema = schemas.ProjectImageSimpleOut
class ProjectLabelDal(DalBase):
def __init__(self, db: AsyncSession):
super(ProjectLabelDal, self).__init__()
self.db = db
self.model = models.ProjectLabel
self.schema = schemas.ProjectLabel
async def check_label_name(
self,
name: str,
pro_id: int,
label_id: int = None
):
wheres = [
models.ProjectLabel.project_id == pro_id,
models.ProjectLabel.label_name == name
]
if label_id:
wheres.append(models.ProjectLabel.id != label_id)
count = await self.get_count(v_where=wheres)
return count > 0
class ProjectImgLabelDal(DalBase):
def __init__(self, db: AsyncSession):
super(ProjectImgLabelDal, self).__init__()
self.db = db
self.model = models.ProjectImgLabel
self.schema = schemas.ProjectImgLabelSimpleOut
class ProjectImgLeaferDal(DalBase):
def __init__(self, db: AsyncSession):
super(ProjectImgLeaferDal, self).__init__()
self.db = db
self.model = models.ProjectImgLeafer
self.schema = schemas.ProjectImgLeaferSimpleOut

View File

@ -0,0 +1 @@
from .project import ProjectLabel, ProjectInfo, ProjectImgLabel, ProjectImgLeafer, ProjectImage

View File

@ -0,0 +1,73 @@
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String, Integer, JSON
from db.db_base import BaseModel
class ProjectInfo(BaseModel):
"""
项目信息表
"""
__tablename__ = "project_info"
__table_args__ = ({'comment': '项目类别表 - 标识项目的类型目前存在的目标识别OCR识别瑕疵检测图像分类'})
project_no: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
project_name: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
type_code: Mapped[str] = mapped_column(String(10))
description: Mapped[str] = mapped_column(String(255))
project_status: Mapped[str] = mapped_column(String(10))
user_id: Mapped[int] = mapped_column(Integer)
dept_id: Mapped[int] = mapped_column(Integer)
train_version: Mapped[int] = mapped_column(Integer)
class ProjectLabel(BaseModel):
"""
项目标签表
"""
__tablename__ = "project_label"
__table_args__ = ({'comment': '项目标签表'})
label_name: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
project_id: Mapped[int] = mapped_column(Integer, nullable=False)
meta: Mapped[dict] = mapped_column(JSON)
class ProjectImage(BaseModel):
"""
项目图片表
"""
__tablename__ = "project_image"
__table_args__ = ({'comment': '项目图片表'})
img_type: Mapped[str] = mapped_column(String(10))
file_name: Mapped[str] = mapped_column(String(64), nullable=False)
image_url: Mapped[str] = mapped_column(String(255), nullable=False)
thumb_image_url: Mapped[str] = mapped_column(String(255), nullable=False)
project_id: Mapped[int] = mapped_column(Integer)
class ProjectImgLeafer(BaseModel):
"""
项目图片leafer表
"""
__tablename__ = "project_img_leafer"
__table_args__ = ({'comment': '项目图片leafer表'})
image_id: Mapped[int] = mapped_column(Integer, nullable=False)
leafer: Mapped[dict] = mapped_column(JSON)
class ProjectImgLabel(BaseModel):
"""
项目图片标签对应表一张图片对应多个label
"""
__tablename__ = "project_img_label"
__table_args__ = ({'comment': '项目图片标签对应表一张图片对应多个label'})
image_id: Mapped[int] = mapped_column(Integer, nullable=False)
label_id: Mapped[int] = mapped_column(Integer, nullable=False)
mark_center_x: Mapped[str] = mapped_column(String(64), nullable=False)
mark_center_y: Mapped[str] = mapped_column(String(64), nullable=False)
mark_width: Mapped[str] = mapped_column(String(64), nullable=False)
mark_height: Mapped[str] = mapped_column(String(64), nullable=False)

View File

@ -0,0 +1,5 @@
from .project_info import ProjectInfoParams
from .project_image import ProjectImageParams
from .project_label import ProjectLabelParams
from .project_img_label import ProjectImgLabelParams
from .project_img_leafer import ProjectImgLeaferParams

View File

@ -0,0 +1,25 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:27
# @File : project_image.py
# @IDE : PyCharm
# @desc : 项目图片信息
from fastapi import Depends, Query
from core.dependencies import Paging, QueryParams
class ProjectImageParams(QueryParams):
def __init__(
self,
img_type: str | None = Query(None, title="图片类别"),
project_id: int | None = Query(None, title="项目id"),
file_name: str | None = Query(None, title="文件名称"),
params: Paging = Depends()
):
super().__init__(params)
self.img_type = img_type
self.project_id = project_id
self.file_name = file_name

View File

@ -0,0 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:29
# @File : project_img_label.py
# @IDE : PyCharm
# @desc : 项目图片标签信息
from fastapi import Depends, Query
from core.dependencies import Paging, QueryParams
class ProjectImgLabelParams(QueryParams):
def __init__(
self,
image_id: int | None = Query(None, title="图片id"),
params: Paging = Depends()
):
super().__init__(params)
self.image_id = image_id

View File

@ -0,0 +1,21 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:29
# @File : project_img_leafer.py
# @IDE : PyCharm
# @desc : 项目图片leafer信息
from fastapi import Depends, Query
from core.dependencies import Paging, QueryParams
class ProjectImgLeaferParams(QueryParams):
def __init__(
self,
image_id: int | None = Query(None, title="图片id"),
params: Paging = Depends()
):
super().__init__(params)
self.image_id = image_id

View File

@ -0,0 +1,28 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:25
# @File : project_info.py
# @IDE : PyCharm
# @desc : 项目信息
from fastapi import Depends, Query
from core.dependencies import Paging, QueryParams
class ProjectInfoParams(QueryParams):
def __init__(
self,
project_name: str | None = Query(None, title="项目名称"),
type_code: str | None = Query(None, title="项目类别"),
dept_id: str | None = Query(None, title="部门id"),
user_id: str | None = Query(None, title="用户id"),
params: Paging = Depends()
):
super().__init__(params)
self.project_name = ("like", project_name)
self.type_code = type_code
self.dept_id = dept_id
self.user_id = user_id

View File

@ -0,0 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:28
# @File : project_label.py
# @IDE : PyCharm
# @desc : 项目标签信息
from fastapi import Depends, Query
from core.dependencies import Paging, QueryParams
class ProjectLabelParams(QueryParams):
def __init__(
self,
project_id: int | None = Query(None, title="项目id"),
params: Paging = Depends()
):
super().__init__(params)
self.project_id = project_id

View File

@ -0,0 +1,5 @@
from .project_info import ProjectInfoIn, ProjectInfoOut, ProjectInfoPagerOut
from .project_image import ProjectImage, ProjectImagePager, ProjectImageOut
from .project_label import ProjectLabel
from .project_img_label import ProjectImgLabelIn
from .project_img_leafer import ProjectImgLeaferLabel, ProjectImgLeaferOut

View File

@ -0,0 +1,38 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:27
# @File : project_image.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, Field, ConfigDict
from core.data_types import DatetimeStr
from typing import Optional
class ProjectImage(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
file_name: Optional[str] = Field(None, description="文件名称")
create_time: DatetimeStr
model_config = ConfigDict(from_attributes=True)
class ProjectImageOut(BaseModel):
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(..., description="项目id")
file_name: Optional[str] = Field(None, description="文件名称")
create_time: DatetimeStr
label_count: Optional[int]
model_config = ConfigDict(from_attributes=True)
class ProjectImagePager(BaseModel):
project_id: Optional[int] = Field(..., description="项目id")
img_type: Optional[str] = Field(None, description="图片类别")
pagerNum: Optional[int] = Field(None, description="当前页码")
pagerSize: Optional[int] = Field(None, description="每页数量")

View File

@ -0,0 +1,18 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:29
# @File : project_img_label.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel
class ProjectImgLabelIn(BaseModel):
label_id: int
mark_center_x: str
mark_center_y: str
mark_width: str
mark_height: str

View File

@ -0,0 +1,25 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:29
# @File : project_img_leafer.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, List
from . import ProjectImgLabelIn
class ProjectImgLeaferLabel(BaseModel):
image_id: Optional[int] = Field(..., description="图片id")
leafer: Optional[dict] = Field(..., description="保存的leafer")
label_infos: List[ProjectImgLabelIn] = Field(..., description="标签框选信息")
class ProjectImgLeaferOut(BaseModel):
image_id: Optional[int] = Field(..., description="图片id")
leafer: Optional[dict] = Field(..., description="保存的leafer")
model_config = ConfigDict(from_attributes=True)

View File

@ -0,0 +1,47 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:25
# @File : project_info.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional
class ProjectInfoIn(BaseModel):
"""项目信息输入"""
project_name: Optional[str] = Field(..., description="项目名称")
type_code: Optional[str] = Field(..., description="项目类型编码")
description: Optional[str] = Field(None, description="项目描述")
model_config = ConfigDict(from_attributes=True)
class ProjectInfoOut(BaseModel):
"""项目信息输出"""
id: Optional[int] = Field(None, description="项目id")
project_no: Optional[str] = Field(..., description="项目编号")
project_name: Optional[str] = Field(..., description="项目名称")
type_code: Optional[str] = Field(..., description="项目类型编码")
description: Optional[str] = Field(None, description="项目描述")
train_version: Optional[int] = Field(None, description="训练版本号")
project_status: Optional[str] = Field(None, description="项目状态")
model_config = ConfigDict(from_attributes=True)
class ProjectInfoPagerOut(BaseModel):
"""项目信息输出"""
id: Optional[int] = Field(None, description="项目id")
project_no: Optional[str] = Field(None, description="项目编号")
project_name: Optional[str] = Field(None, description="项目名称")
type_code: Optional[str] = Field(None, description="项目类型编码")
description: Optional[str] = Field(None, description="项目描述")
train_version: Optional[int] = Field(None, description="训练版本号")
project_status: Optional[str] = Field(None, description="项目状态")
mark_count: Optional[int] = Field(0, description="已标记数量")
no_mark_count: Optional[int] = Field(0, description="未标记数量")
model_config = ConfigDict(from_attributes=True)

View File

@ -0,0 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:28
# @File : project_label.py
# @IDE : PyCharm
# @desc : pydantic 模型,用于数据库序列化操作
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional
class ProjectLabel(BaseModel):
"""项目标签输入输出"""
id: Optional[int] = Field(None, description="id")
project_id: Optional[int] = Field(None, description="项目id")
label_name: Optional[str] = Field(..., description="标签名称")
meta: Optional[dict] = Field(None, description="label属性")
model_config = ConfigDict(from_attributes=True)

View File

@ -0,0 +1,107 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @version : 1.0
# @Create Time : 2025/04/03 10:25
# @File : views.py
# @IDE : PyCharm
# @desc : 路由,视图文件
from utils.response import SuccessResponse, ErrorResponse
from . import params, schemas, crud, models
from core.dependencies import IdList
from fastapi import APIRouter, Depends
from apps.vadmin.auth.utils.current import FullAdminAuth
from apps.vadmin.auth.utils.validation.auth import Auth
app = APIRouter()
###########################################################
# 项目信息
###########################################################
@app.get("/list", summary="获取项目信息列表")
async def project_pager(
param: params.ProjectInfoParams = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
datas, count = await crud.ProjectInfoDal(auth.db).get_project_pager(project=param, auth=auth)
return SuccessResponse(datas, count=count)
@app.post("/info", summary="新建项目")
async def add_project(
pro_in: schemas.ProjectInfoIn,
auth: Auth = Depends(FullAdminAuth())
):
check = await crud.ProjectInfoDal(auth.db).check_name(project_name=pro_in.project_name)
if check:
return ErrorResponse(msg="存在相同名称的项目,不能创建")
result = await crud.ProjectInfoDal(auth.db).add_project(pro_in, auth)
return SuccessResponse(data=result)
@app.get("/info/{pro_id}", summary="查询项目信息")
async def project(
pro_id: int,
auth: Auth = Depends(FullAdminAuth())
):
result = await crud.ProjectInfoDal(auth.db).get_data(data_id=pro_id, v_schema=schemas.ProjectInfoOut)
return SuccessResponse(data=result)
@app.delete("/info", summary="删除项目")
async def del_project(
pro_ids: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectInfoDal(auth.db).delete_datas(ids=pro_ids.ids, v_soft=True)
return SuccessResponse(msg="删除成功")
@app.get("/label/{pro_id}", summary="查询标签列表")
async def label_list(
pro_id: int,
auth: Auth = Depends(FullAdminAuth())
):
result = await crud.ProjectLabelDal(auth.db).get_datas(v_where=[models.ProjectLabel.project_id == pro_id],
v_schema=schemas.ProjectLabel)
return SuccessResponse(data=result)
@app.post("/label", summary="新建标签")
async def add_label(
label_in: schemas.ProjectLabel,
auth: Auth = Depends(FullAdminAuth())
):
check = await crud.ProjectLabelDal(auth.db).check_label_name(label_in.label_name, label_in.project_id)
if check:
return ErrorResponse(msg="存在相同名称的标签,不能新建")
await crud.ProjectLabelDal(auth.db).create_data(data=label_in)
return SuccessResponse(msg="新建成功")
@app.put("/label", summary="修改标签")
async def update_label(
label_in: schemas.ProjectLabel,
auth: Auth = Depends(FullAdminAuth())
):
check = await crud.ProjectLabelDal(auth.db).check_label_name(label_in.label_name, label_in.project_id, label_in.id)
if check:
return ErrorResponse(msg="存在相同名称的标签,不能修改")
await crud.ProjectLabelDal(auth.db).put_data(data_id=label_in.id, data=label_in)
return SuccessResponse(msg="修改成功")
@app.delete("/label", summary="删除标签")
async def delete_label(
label_ids: IdList = Depends(),
auth: Auth = Depends(FullAdminAuth())
):
await crud.ProjectLabelDal(auth.db).delete_datas(label_ids.ids)
return SuccessResponse(msg="删除成功")