commit 39d38c85443b7e335a209385f1a84025014f5fc0 Author: liuyebo <1515783401@qq.com> Date: Fri May 17 16:16:56 2024 +0800 首次提交 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..04602a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +photo_review/service/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + diff --git a/auto_generator.py b/auto_generator.py new file mode 100644 index 0000000..d9a3dd4 --- /dev/null +++ b/auto_generator.py @@ -0,0 +1,14 @@ +# 自动生成数据库表和sqlalchemy对应的Model +import subprocess + +from config.mysql import DB_URL + +table = input("请输入表名:") +out_file = f"photo_review/entity/{table}.py" +command = f"sqlacodegen {DB_URL} --outfile={out_file} --tables={table}" + +try: + subprocess.run(command, shell=True, check=True) + print(f"{table}.py文件生成成功!请手动调整Base的声明!") +except Exception as e: + print(f"生成{table}.py文件时发生错误: {e}") diff --git a/config/log.py b/config/log.py new file mode 100644 index 0000000..a8392eb --- /dev/null +++ b/config/log.py @@ -0,0 +1,41 @@ +# 配置字典 +LOGGING_CONFIG = { + 'version': 1, # 必需,指定配置格式的版本 + 'disable_existing_loggers': False, # 是否禁用已经存在的logger实例 + + # formatters定义了不同格式的日志样式 + 'formatters': { + 'standard': { + 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s', + 'datefmt': '%Y-%m-%d %H:%M:%S', + }, + }, + + # handlers定义了不同类型的日志处理器 + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', # 控制台处理器 + 'level': 'DEBUG', + 'formatter': 'standard', + 'stream': 'ext://sys.stdout', # 输出到标准输出,默认编码跟随系统,一般为UTF-8 + }, + 'file': { + 'class': 'logging.handlers.RotatingFileHandler', # 文件处理器,支持日志滚动 + 'level': 'INFO', + 'formatter': 'standard', + 'filename': 'log/fcb_photo_review.log', # 日志文件路径 + 'maxBytes': 1024 * 1024 * 5, # 文件最大大小,这里为5MB + 'backupCount': 5, # 保留的备份文件数量 + 'encoding': 'utf-8', # 显式指定文件编码为UTF-8以支持中文 + }, + }, + + # loggers定义了日志记录器,这里是根记录器 + 'loggers': { + '': { # 根记录器 + 'handlers': ['console', 'file'], # 关联的处理器 + 'level': 'DEBUG', # 根记录器的级别 + 'propagate': False, # 是否向上级传播日志信息 + }, + }, +} diff --git a/config/mysql.py b/config/mysql.py new file mode 100644 index 0000000..93d3826 --- /dev/null +++ b/config/mysql.py @@ -0,0 +1,23 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +# 数据库地址 +HOSTNAME = '192.168.5.226' +# 端口号 +PORT = '3308' +# 库名 +DATABASE = 'wzxtest' +# 用户名 +USERNAME = 'root' +# 密码 +PASSWORD = 'test9Root' +# 把配置信息和以上的连接数据组合 +DB_URL = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}' + +# 是否打印执行的sql +SHOW_SQL = False + +Engine = create_engine(DB_URL, echo=SHOW_SQL) +Base = declarative_base(Engine) +MysqlSession = sessionmaker(bind=Engine) diff --git a/main.py b/main.py new file mode 100644 index 0000000..d19e406 --- /dev/null +++ b/main.py @@ -0,0 +1,11 @@ +import logging.config + +from config.log import LOGGING_CONFIG +from photo_review.photo_review import main + +# 项目必须从此处启动,否则代码中的相对路径可能导致错误的发生 +if __name__ == '__main__': + logging.config.dictConfig(LOGGING_CONFIG) + log = logging.getLogger() + log.info("照片审核开始") + main() diff --git a/photo_review/__init__.py b/photo_review/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/photo_review/entity/__init__.py b/photo_review/entity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/photo_review/entity/bd_yljg.py b/photo_review/entity/bd_yljg.py new file mode 100644 index 0000000..66210d8 --- /dev/null +++ b/photo_review/entity/bd_yljg.py @@ -0,0 +1,29 @@ +# coding: utf-8 +from sqlalchemy import Column, DateTime, String, text +from sqlalchemy.dialects.mysql import INTEGER, TINYINT + +from config.mysql import Base + + +class BdYljg(Base): + __tablename__ = 'bd_yljg' + + pk_yljg = Column(INTEGER(11), primary_key=True, comment='医疗机构主键') + code = Column(String(12), nullable=False, unique=True, comment='编码') + name = Column(String(200), comment='名称') + cpym = Column(String(40), comment='拼音码') + pk_yldj = Column(INTEGER(11), comment='医疗机构等级') + pk_father = Column(INTEGER(11), comment='上级医疗机构') + address = Column(String(300), comment='地址') + pk_region = Column(INTEGER(11), comment='行政区划主键') + depiction = Column(String(100), comment='备注') + creator = Column(String(20), comment='创建人') + creationtime = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='创建时间') + modifier = Column(String(20), comment='最后修改人') + modifiedtime = Column(DateTime, comment='最后修改时间') + enablestate = Column(TINYINT(4), server_default=text("'1'"), comment='启用状态') + create_by = Column(String(100), comment='创建人') + create_time = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='创建时间') + update_by = Column(String(100), comment='更新人') + update_time = Column(DateTime, comment='更新时间') + del_flag = Column(TINYINT(1), server_default=text("'0'"), comment='删除标记') diff --git a/photo_review/entity/bd_ylks.py b/photo_review/entity/bd_ylks.py new file mode 100644 index 0000000..a168a96 --- /dev/null +++ b/photo_review/entity/bd_ylks.py @@ -0,0 +1,27 @@ +# coding: utf-8 +from sqlalchemy import CHAR, Column, DateTime, String, text +from sqlalchemy.dialects.mysql import INTEGER, TINYINT + +from config.mysql import Base + + +class BdYlks(Base): + __tablename__ = 'bd_ylks' + + pk_ylks = Column(INTEGER(11), primary_key=True, comment='科室主键') + code = Column(String(12), nullable=False, index=True, comment='编码') + name = Column(String(200), comment='名称') + cpym = Column(String(40), comment='拼音码') + pk_father = Column(INTEGER(11)) + cIsBottom = Column(CHAR(1), comment='是否底层') + depiction = Column(String(100), comment='备注') + creator = Column(String(20), comment='创建人') + creationtime = Column(DateTime, comment='创建时间') + modifier = Column(String(20), comment='最后修改人') + modifiedtime = Column(DateTime, comment='最后修改时间') + enablestate = Column(TINYINT(4), server_default=text("'1'"), comment='启用状态') + create_by = Column(String(100), comment='创建人') + create_time = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='创建时间') + update_by = Column(String(100), comment='更新人') + update_time = Column(DateTime, comment='更新时间') + del_flag = Column(TINYINT(1), server_default=text("'0'"), comment='删除标记') diff --git a/photo_review/entity/zx_ie_cost.py b/photo_review/entity/zx_ie_cost.py new file mode 100644 index 0000000..b67b593 --- /dev/null +++ b/photo_review/entity/zx_ie_cost.py @@ -0,0 +1,23 @@ +# coding: utf-8 +from sqlalchemy import Column, DECIMAL, Date, DateTime, String +from sqlalchemy.dialects.mysql import INTEGER + +from config.mysql import Base + + +class ZxIeCost(Base): + __tablename__ = 'zx_ie_cost' + + pk_ie_cost = Column(INTEGER(11), primary_key=True, comment='费用明细信息抽取主键') + pk_phhd = Column(INTEGER(11), nullable=False, unique=True, comment='报销案子主键') + name = Column(String(30), comment='患者姓名') + admission_date_str = Column(String(255), comment='入院日期字符串') + admission_date = Column(Date, comment='入院日期') + discharge_date_str = Column(String(255), comment='出院日期字符串') + discharge_date = Column(Date, comment='出院日期') + medical_expenses_str = Column(String(255), comment='费用总额字符串') + medical_expenses = Column(DECIMAL(18, 2), comment='费用总额') + createtime = Column(DateTime, comment='创建时间') + creator = Column(String(255), comment='创建人') + modifiedtime = Column(DateTime, comment='修改时间') + modifier = Column(String(255), comment='修改人') diff --git a/photo_review/entity/zx_ie_discharge.py b/photo_review/entity/zx_ie_discharge.py new file mode 100644 index 0000000..6196f2f --- /dev/null +++ b/photo_review/entity/zx_ie_discharge.py @@ -0,0 +1,26 @@ +# coding: utf-8 +from sqlalchemy import Column, Date, DateTime, String +from sqlalchemy.dialects.mysql import INTEGER + +from config.mysql import Base + + +class ZxIeDischarge(Base): + __tablename__ = 'zx_ie_discharge' + + pk_ie_discharge = Column(INTEGER(11), primary_key=True, comment='出院记录信息抽取主键') + pk_phhd = Column(INTEGER(11), nullable=False, unique=True, comment='报销案子主键') + hospital = Column(String(255), comment='医院') + pk_yljg = Column(INTEGER(11), comment='医院主键') + department = Column(String(255), comment='科别') + pk_ylks = Column(INTEGER(11), comment='科别主键') + name = Column(String(30), comment='患者姓名') + admission_date_str = Column(String(255), comment='入院日期字符串') + admission_date = Column(Date, comment='入院日期') + discharge_date_str = Column(String(255), comment='出院日期字符串') + discharge_date = Column(Date, comment='出院日期') + doctor = Column(String(30), comment='主治医师') + createtime = Column(DateTime, comment='创建时间') + creator = Column(String(255), comment='创建人') + modifiedtime = Column(DateTime, comment='修改时间') + modifier = Column(String(255), comment='修改人') diff --git a/photo_review/entity/zx_ie_settlement.py b/photo_review/entity/zx_ie_settlement.py new file mode 100644 index 0000000..ecfc56b --- /dev/null +++ b/photo_review/entity/zx_ie_settlement.py @@ -0,0 +1,30 @@ +# coding: utf-8 +from sqlalchemy import Column, DECIMAL, Date, DateTime, String +from sqlalchemy.dialects.mysql import INTEGER + +from config.mysql import Base + + +class ZxIeSettlement(Base): + __tablename__ = 'zx_ie_settlement' + + pk_ie_settlement = Column(INTEGER(11), primary_key=True, comment='结算清单信息抽取主键') + pk_phhd = Column(INTEGER(11), nullable=False, unique=True, comment='报销案子主键') + name = Column(String(30), comment='患者姓名') + admission_date_str = Column(String(255), comment='入院日期字符串') + admission_date = Column(Date, comment='入院日期') + discharge_date_str = Column(String(255), comment='出院日期字符串') + discharge_date = Column(Date, comment='出院日期') + medical_expenses_str = Column(String(255), comment='费用总额字符串') + medical_expenses = Column(DECIMAL(18, 2), comment='费用总额') + personal_cash_payment_str = Column(String(255), comment='个人现金支付字符串') + personal_cash_payment = Column(DECIMAL(18, 2), comment='个人现金支付') + personal_account_payment_str = Column(String(255), comment='个人账户支付字符串') + personal_account_payment = Column(DECIMAL(18, 2), comment='个人账户支付') + personal_funded_amount_str = Column(String(255), comment='自费金额字符串') + personal_funded_amount = Column(DECIMAL(18, 2), comment='自费金额') + medical_insurance_type = Column(String(255), comment='医保类型') + createtime = Column(DateTime, comment='创建时间') + creator = Column(String(255), comment='创建人') + modifiedtime = Column(DateTime, comment='修改时间') + modifier = Column(String(255), comment='修改人') diff --git a/photo_review/entity/zx_phhd.py b/photo_review/entity/zx_phhd.py new file mode 100644 index 0000000..aeb0a23 --- /dev/null +++ b/photo_review/entity/zx_phhd.py @@ -0,0 +1,115 @@ +# coding: utf-8 +from sqlalchemy import Column, DECIMAL, Date, DateTime, Index, String, text +from sqlalchemy.dialects.mysql import BIT, CHAR, INTEGER, TINYINT, VARCHAR + +from config.mysql import Base + + +class ZxPhhd(Base): + __tablename__ = 'zx_phhd' + __table_args__ = ( + Index('zx_phhd_idx7', 'pk_yljg', 'cjsd_id'), + Index('zx_phhd_idx5', 'cStatus', 'checker', 'checktime') + ) + + pk_phhd = Column(INTEGER(11), primary_key=True, comment='病案主键') + cPhhd_id = Column(VARCHAR(20), unique=True, comment='拍一拍单据号') + billdate = Column(DateTime, index=True) + pk_person = Column(INTEGER(11), server_default=text("'0'"), comment='人员主键') + pk_corp = Column(INTEGER(11), index=True, server_default=text("'0'"), comment='单位主键') + cRyid = Column(VARCHAR(20), comment='人员编码') + cJBH = Column(VARCHAR(20), comment='结报号') + cXm = Column(String(12), comment='姓名') + cSfzh = Column(VARCHAR(20), index=True, comment='身份证号') + czh = Column(VARCHAR(20), comment='小组') + cXb = Column(VARCHAR(2), comment='性别') + dCsny = Column(Date, comment='出身时间') + fAge = Column(INTEGER(4), server_default=text("'0'"), comment='年龄') + pk_yljg = Column(INTEGER(11), server_default=text("'0'"), comment='医院pk') + pk_ylks = Column(INTEGER(11), server_default=text("'0'"), comment='科室pk') + cDoctor = Column(VARCHAR(20), comment='医生') + dZYRQ = Column(DateTime, comment='入院日期') + dCYRQ = Column(DateTime) + cZYH = Column(VARCHAR(20), comment='住院号') + iMZTS = Column(INTEGER(4), server_default=text("'0'"), comment='住院天数') + fFSYLFY = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='发生医疗费用') + fZcfwfy = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='政策范围内费用') + fxnhbcje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='新农合补助金额') + fqtbcje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='其它补助金额') + fBCJE = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='补偿金额') + fgrzfje1 = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额1') + fgezfje2 = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额2') + fgrzfje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人自费金额') + fZfje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='自付金额') + fXianje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='限额') + fMaxbcje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='最高支付') + cJBBM = Column(VARCHAR(20), server_default=text("'-'"), comment='疾病编码') + cJbbm_cyzd = Column(VARCHAR(20), comment='疾病编码出院诊断') + cSsczmc = Column(VARCHAR(100), comment='手术操作名称') + problem_note = Column(String(400)) + depiction = Column(VARCHAR(300), comment='备注') + creator = Column(VARCHAR(30), index=True, comment='创建人') + creationtime = Column(DateTime, index=True, server_default=text("CURRENT_TIMESTAMP"), comment='创建时间') + modifier = Column(VARCHAR(30), comment='最后修改人') + modifiedtime = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='最后修改时间') + cStatus = Column(CHAR(1), server_default=text("'0'"), comment='状态') + vercode = Column(VARCHAR(4), comment='版本编码') + cSource_flag = Column(VARCHAR(4), server_default=text("'1'"), comment='病案来源') + ref_id1 = Column(VARCHAR(20)) + ref_id2 = Column(VARCHAR(20)) + ref_pk1 = Column(INTEGER(11)) + checker = Column(VARCHAR(30), comment='创建人') + checktime = Column(DateTime, comment='创建时间') + paint_user = Column(VARCHAR(30)) + paint_date = Column(DateTime) + filetype_id = Column(VARCHAR(10), comment='文件类型id') + cMphone = Column(VARCHAR(11), comment='移动电话') + cmiss_rectype = Column(VARCHAR(10), comment='遗漏记录类型') + cmiss_remark = Column(VARCHAR(200), comment='遗漏备注 ') + bhg_remark = Column(VARCHAR(200), comment='不合格原因') + cmis_jsd_flag = Column(BIT(1)) + cmis_jsd_page = Column(VARCHAR(40), comment='结算单遗漏页码') + cmis_cyjl_flag = Column(BIT(1)) + cmis_cyjl_page = Column(VARCHAR(40), comment='出院记录遗漏页码') + cmis_fyqd_flag = Column(BIT(1)) + cmis_fyqd_page = Column(VARCHAR(40), comment='费用清单遗漏页码') + cmis_evidence = Column(VARCHAR(60), comment='相关证明材料') + del_reason = Column(CHAR(1), server_default=text("'0'"), comment='删除原因') + deln_reason = Column(VARCHAR(2), comment='删除原因') + train_flag = Column(VARCHAR(10), server_default=text("'0'"), comment='培训标志') + cjsd_id = Column(VARCHAR(30), comment='结算单号码') + sms_content = Column(String(1000), comment='短信内容') + judge_backup = Column(VARCHAR(100)) + remind_num = Column(INTEGER(11), server_default=text("'0'"), comment='提醒次数') + input_cxm = Column(String(20), comment='姓名核对') + yb_type = Column(VARCHAR(10), comment='医保类别') + bucode = Column(VARCHAR(4), server_default=text("'1'"), comment='业务单元') + subcorpname = Column(VARCHAR(80), comment='子公司') + deptname = Column(VARCHAR(80), comment='部门') + psncode = Column(VARCHAR(16), comment='工号') + period_code = Column(VARCHAR(10), comment='会计期间') + cbznote = Column(VARCHAR(500)) + corp_list = Column(VARCHAR(200), comment='其它补助单位及年度') + perjudge_flag = Column(CHAR(1), server_default=text("'0'"), comment='人员信息判断标志') + priority_num = Column(TINYINT(4), server_default=text("'0'"), comment='优先领取') + addin_xybz = Column(BIT(1)) + addin_tybz = Column(BIT(1)) + finish_flag = Column(BIT(1)) + exsuccess_flag = Column(BIT(1)) + pk_soncorp = Column(INTEGER(11), server_default=text("'0'"), comment='镇下村单位pk值') + return_times = Column(INTEGER(11), server_default=text("'0'"), comment='退回次数') + phuser_type = Column(CHAR(1), server_default=text("'1'"), comment='拍传人类型(1-自拍,2代拍,3管理员代拍)') + examine_note = Column(VARCHAR(400), comment='抽查意见') + examine_user = Column(VARCHAR(30), comment='抽查人') + examine_date = Column(DateTime, comment='抽查时间') + channel_code = Column(VARCHAR(10), comment='上传渠道') + einvoice_flag = Column(BIT(1)) + drgs_flag = Column(CHAR(1), server_default=text("'0'"), comment='病种类型(0-无,1-单病种,2-drg)') + applyDate = Column(DateTime) + admissionDate = Column(Date, comment='入院日期') + dischargeDate = Column(Date, comment='出院日期') + reapplyDate = Column(Date, comment='重新上传日期') + exreq_times = Column(INTEGER(11), server_default=text("'0'"), comment='请求次数') + drug_source = Column(CHAR(1), server_default=text("'0'"), comment='药品来源(1-外购药,0--没有)') + addin_passpaydate = Column(BIT(1)) + apply_classid = Column(CHAR(1), server_default=text("'0'"), comment='申请人员类别(1-农民工,0-默认)') diff --git a/photo_review/entity/zx_phrec.py b/photo_review/entity/zx_phrec.py new file mode 100644 index 0000000..613c82f --- /dev/null +++ b/photo_review/entity/zx_phrec.py @@ -0,0 +1,46 @@ +# coding: utf-8 +from sqlalchemy import CHAR, Column, DateTime, LargeBinary, String, text +from sqlalchemy.dialects.mysql import BIT, INTEGER, TINYINT + +from config.mysql import Base + + +class ZxPhrec(Base): + __tablename__ = 'zx_phrec' + + pk_phrec = Column(INTEGER(11), primary_key=True, comment='病案清主键') + pk_phhd = Column(INTEGER(11), index=True, comment='病案主键') + cRectype = Column(CHAR(1), comment='记录类型(1-入院小结,2--出院小结,3--手术记录 4清单)') + rowno = Column(TINYINT(4), server_default=text("'1'"), comment='序号') + cfjaddress = Column(String(200), comment='附件地址') + cfjaddress2 = Column(String(500), comment='附件地址2') + cfjaddress3 = Column(String(500), comment='附件地址3') + cfjblob = Column(LargeBinary, comment='附件') + cfjblob2 = Column(LargeBinary, comment='附件2') + cfjblob3 = Column(LargeBinary, comment='附件3') + subsys_id = Column(String(4), comment='分系统代码') + depiction = Column(String(100), comment='备注') + isreupload = Column(CHAR(1), server_default=text("'0'")) + checker = Column(String(10), comment='创建人') + checktime = Column(DateTime, comment='创建时间') + creator = Column(String(30), comment='创建人') + creationtime = Column(DateTime, index=True, comment='创建时间') + modifier = Column(String(30), comment='最后修改人') + modifiedtime = Column(DateTime, comment='最后修改时间') + cSource_flag = Column(String(4), server_default=text("'1'"), comment='病案来源') + cStatus = Column(CHAR(1), server_default=text("'0'"), comment='状态') + link_flag = Column(CHAR(1), server_default=text("'1'"), comment='是否采用链接') + filetype_id = Column(String(10), server_default=text("'jpg'"), comment='文件类型id') + cmiss_flag = Column(INTEGER(4), server_default=text("'0'"), comment='遗漏补拍标记') + paint_flag = Column(CHAR(1), server_default=text("'0'"), comment='涂抹标志') + paint_user = Column(String(30)) + paint_date = Column(DateTime) + byz_xmbz_flag = Column(BIT(1)) + byz_zyrqcyjl_flag = Column(BIT(1)) + byz_zyhcyjl_flag = Column(BIT(1)) + byz_ftyccyjl_flag = Column(BIT(1)) + byz_ftycfyqd_flag = Column(BIT(1)) + byz_ftycjsd_flag = Column(BIT(1)) + unsharp_flag = Column(BIT(1)) + judge_backup = Column(String(40)) + ps_flag = Column(CHAR(1), server_default=text("'0'"), comment='图片是否ps过(0-无,1-ps过)') diff --git a/photo_review/photo_review.py b/photo_review/photo_review.py new file mode 100644 index 0000000..01f0a7d --- /dev/null +++ b/photo_review/photo_review.py @@ -0,0 +1,197 @@ +from time import sleep + +from paddlenlp import Taskflow + +from config.mysql import MysqlSession +from photo_review.entity.bd_yljg import BdYljg +from photo_review.entity.bd_ylks import BdYlks +from photo_review.entity.zx_ie_cost import ZxIeCost +from photo_review.entity.zx_ie_discharge import ZxIeDischarge +from photo_review.entity.zx_ie_settlement import ZxIeSettlement +from photo_review.entity.zx_phhd import ZxPhhd +from photo_review.entity.zx_phrec import ZxPhrec +from photo_review.util.data_util import handle_date, handle_decimal +from photo_review.util.ucloud import get_private_url + + +# 关键信息提取 +def information_extraction(schema, pictures, task_path): + results = {} + for picture in pictures: + pic_path = get_private_url(picture) + if pic_path: + ie = Taskflow("information_extraction", schema=schema, model="uie-x-base", task_path=task_path) + result = ie({"doc": pic_path}) + results.update(result[0]) + return results + + +# 从keys中获取第一个不为空的value +def get_value_in_keys(source, keys): + for key in keys: + value = source.get(key) + if value: + value = value[0].get("text") + if value: + return value + return None + + +# 从keys中获取所有value组成list +def get_values_of_keys(source, keys): + result = [] + for key in keys: + value = source.get(key) + if value: + value = value[0].get("text") + if value: + result.append(value) + return result + + +def save_or_update_ie(table, pk_phhd, data): + data = {k: v for k, v in data.items() if v is not None and v != ""} + obj = table(**data) + session = MysqlSession() + db_data = session.query(table).filter_by(pk_phhd=pk_phhd).one_or_none() + if db_data: + for k, v in data.items(): + setattr(db_data, k, v) + else: + session.add(obj) + session.commit() + session.close() + + +def photo_review(pk_phhd): + settlement_list = [] + discharge_record = [] + cost_list = [] + + session = MysqlSession() + phrecs = session.query(ZxPhrec.pk_phrec, ZxPhrec.cRectype, ZxPhrec.cfjaddress) \ + .filter(ZxPhrec.pk_phhd == pk_phhd) \ + .all() + session.close() + for phrec in phrecs: + if phrec.cRectype == "1": + settlement_list.append(phrec.cfjaddress) + elif phrec.cRectype == "3": + discharge_record.append(phrec.cfjaddress) + elif phrec.cRectype == "4": + cost_list.append(phrec.cfjaddress) + + name_key = ["姓名", "交款人"] + admission_date_key = ["入院日期", "住院时间", "开始日期", "费用发生时间", "入院时间", "住院日期"] + discharge_date_key = ["出院日期", "结束日期", "出院时间"] + medical_expenses_key = ["费用总额", "总费用", "医疗费用总额", "总计", "合计", "金额合计", "总金额", "本次住院费用总金额", "价税合计", + "合计金额", "费用合计", "项目合计"] + personal_cash_payment_key = ["个人现金支付", "个人支付金额", "个人现金支出", "现金支付", "实际现金", "个人负担总金额", "本次现金", + "医院收取病人金额", "个人付现", "个人现金", "自费金额"] + personal_account_payment_key = ["个人账户支付", "账户支付", "个人账户支出", "个账支付", "账户支出"] + personal_funded_amount_key = ["自费", "全自费金额", "个人自费", "范围外费用", "超限价自费费用", "目录外自费", "自费总额", "自费费用"] + medical_insurance_type_key = ["医保类型"] + hospital_key = ["医院", "就诊医院", "医院名称", "医学中心"] + department_key = ["科别", "病人科室", "住院科别", "科室", "住院科室", "科室名称"] + doctor_key = ["主治医师", "住院医师", "医师", "主治及以上医师签名", "主治医生签名", "医生签名", "主治医师签名", "医师签名", "上级医师", + "主诊医师", "经治医师", "副主任中医师号"] + + # 基本医保结算单 + settlement_list_schema = \ + name_key + admission_date_key + discharge_date_key + medical_expenses_key + personal_cash_payment_key \ + + personal_account_payment_key + personal_funded_amount_key + medical_insurance_type_key + # 出院记录 + discharge_record_schema = \ + hospital_key + department_key + name_key + admission_date_key + discharge_date_key + doctor_key + # 费用清单 + cost_list_schema = name_key + admission_date_key + discharge_date_key + medical_expenses_key + + settlement_list_ie_result = information_extraction(settlement_list_schema, settlement_list, + "config/model/settlement_list_model") + settlement_data = { + "pk_phhd": pk_phhd, + "name": get_value_in_keys(settlement_list_ie_result, name_key), + "admission_date_str": get_value_in_keys(settlement_list_ie_result, admission_date_key), + "discharge_date_str": get_value_in_keys(settlement_list_ie_result, discharge_date_key), + "medical_expenses_str": get_value_in_keys(settlement_list_ie_result, medical_expenses_key), + "personal_cash_payment_str": get_value_in_keys(settlement_list_ie_result, personal_cash_payment_key), + "personal_account_payment_str": get_value_in_keys(settlement_list_ie_result, personal_account_payment_key), + "personal_funded_amount_str": get_value_in_keys(settlement_list_ie_result, personal_funded_amount_key), + "medical_insurance_type": get_value_in_keys(settlement_list_ie_result, medical_insurance_type_key) + } + settlement_data["admission_date"] = handle_date(settlement_data["admission_date_str"]) + settlement_data["admission_date"] = handle_date(settlement_data["admission_date_str"]) + settlement_data["discharge_date"] = handle_date(settlement_data["discharge_date_str"]) + settlement_data["medical_expenses"] = handle_decimal(settlement_data["medical_expenses_str"]) + settlement_data["personal_cash_payment"] = handle_decimal(settlement_data["personal_cash_payment_str"]) + settlement_data["personal_account_payment"] = handle_decimal(settlement_data["personal_account_payment_str"]) + settlement_data["personal_funded_amount"] = handle_decimal(settlement_data["personal_funded_amount_str"]) + save_or_update_ie(ZxIeSettlement, pk_phhd, settlement_data) + + discharge_record_ie_result = information_extraction(discharge_record_schema, discharge_record, + "config/model/discharge_record_model") + discharge_data = { + "pk_phhd": pk_phhd, + "hospital": get_value_in_keys(discharge_record_ie_result, hospital_key), + "department": get_value_in_keys(discharge_record_ie_result, department_key), + "name": get_value_in_keys(discharge_record_ie_result, name_key), + "admission_date_str": get_value_in_keys(discharge_record_ie_result, admission_date_key), + "discharge_date_str": get_value_in_keys(discharge_record_ie_result, discharge_date_key), + "doctor": get_value_in_keys(discharge_record_ie_result, doctor_key) + } + discharge_data["admission_date"] = handle_date(discharge_data["admission_date_str"]) + discharge_data["discharge_date"] = handle_date(discharge_data["discharge_date_str"]) + hospital_value = get_values_of_keys(discharge_record_ie_result, hospital_key) + if hospital_value: + session = MysqlSession() + yljg = session.query(BdYljg.pk_yljg, BdYljg.name) \ + .filter(BdYljg.name.in_(hospital_value)).limit(1).one_or_none() + session.close() + if yljg: + discharge_data["pk_yljg"] = yljg.pk_yljg + discharge_data["hospital"] = yljg.name + department_value = get_values_of_keys(discharge_record_ie_result, department_key) + if department_value: + session = MysqlSession() + ylks = session.query(BdYlks.pk_ylks, BdYlks.name) \ + .filter(BdYlks.name.in_(department_value)).limit(1).one_or_none() + session.close() + if ylks: + discharge_data["pk_ylks"] = ylks.pk_ylks + discharge_data["department"] = ylks.name + save_or_update_ie(ZxIeDischarge, pk_phhd, discharge_data) + + cost_list_ie_result = information_extraction(cost_list_schema, cost_list, "config/model/cost_list_model") + cost_data = { + "pk_phhd": pk_phhd, + "name": get_value_in_keys(cost_list_ie_result, name_key), + "admission_date_str": get_value_in_keys(cost_list_ie_result, admission_date_key), + "discharge_date_str": get_value_in_keys(cost_list_ie_result, discharge_date_key), + "medical_expenses_str": get_value_in_keys(cost_list_ie_result, medical_expenses_key) + } + cost_data["admission_date"] = handle_date(cost_data["admission_date_str"]) + cost_data["discharge_date"] = handle_date(cost_data["discharge_date_str"]) + cost_data["medical_expenses"] = handle_date(cost_data["medical_expenses_str"]) + save_or_update_ie(ZxIeCost, pk_phhd, cost_data) + + +def main(): + # 最后处理的报销案子pk + last_pk_phhd = 0 + # 持续检测新案子 + while 1: + session = MysqlSession() + phhds = session.query(ZxPhhd.pk_phhd) \ + .filter(ZxPhhd.pk_phhd > last_pk_phhd) \ + .filter(ZxPhhd.cStatus == '2') \ + .limit(1) \ + .all() + session.close() + if phhds: + for phhd in phhds: + pk_phhd = phhd.pk_phhd + photo_review(pk_phhd) + last_pk_phhd = pk_phhd + else: + # 没有查询到新案子,等待 5 分钟后再查 + sleep(5 * 60) diff --git a/photo_review/util/__init__.py b/photo_review/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/photo_review/util/data_util.py b/photo_review/util/data_util.py new file mode 100644 index 0000000..a6f951c --- /dev/null +++ b/photo_review/util/data_util.py @@ -0,0 +1,50 @@ +import re +from datetime import datetime + + +# 处理金额类数据 +def handle_decimal(string): + if not string: + return "" + return re.sub(r'[^0-9.]', '', string) + + +# 处理日期类数据 +def handle_date(string): + if not string: + return "" + + string = string.replace("年", "-").replace("月", "-").replace("日", "") + string = re.sub(r'[^0-9-]', '', string) + if is_valid_date_format(string): + return string + else: + return "" + + +# 判断是否是合法的日期格式 +def is_valid_date_format(date_str): + if len(date_str) < 6: + return False + + # 定义可能的日期格式 + formats = [ + # yyyy-MM-dd + '%Y-%m-%d', + # yy-MM-dd + '%y-%m-%d', + # yyyyMMdd + '%Y%m%d', + # yyMMdd + '%y%m%d', + ] + + # 遍历所有格式,尝试解析日期 + for fmt in formats: + try: + datetime.strptime(date_str, fmt) + return True + except ValueError: + pass + + return False diff --git a/photo_review/util/ucloud.py b/photo_review/util/ucloud.py new file mode 100644 index 0000000..b95120b --- /dev/null +++ b/photo_review/util/ucloud.py @@ -0,0 +1,27 @@ +# https://github.com/ucloud/ufile-sdk-python +import logging + +from ufile import filemanager + +public_key = "4Z7QYI7qml36QRjcCjKrls7aHl1R6H6uq" +private_key = "FIdW1Kev1Ge3K7GHXzSLyGG1wTnaG6LE9BxmIVubcCaG" +bucket = "drg100" +upload_suffix = ".cn-sh2.ufileos.com" +download_suffix = ".cn-sh2.ufileos.com" + + +def get_private_url(key): + get_ufile_handler = filemanager.FileManager(public_key, private_key, upload_suffix, download_suffix) + + # 判断文件是否存在 + _, resp = get_ufile_handler.head_file(bucket, key) + if resp.status_code != 200: + logging.warning("uCloud中未找到(%s)! status: %d error: %s", key, resp.status_code, resp.error) + return None + + # 获取公有空间下载url + # url = get_ufile_handler.public_download_url(bucket, key) + + # 获取私有空间下载url, expires为下载链接有效期,单位为秒 + url = get_ufile_handler.private_download_url(bucket, key, expires=60) + return url diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ba23fe4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +paddlenlp==2.6.1 +sqlacodegen==2.3.0.post1 +ufile==3.2.9 diff --git a/test/visual_model_test/img/PH20240401000003_3_001938_2.jpg b/test/visual_model_test/img/PH20240401000003_3_001938_2.jpg new file mode 100644 index 0000000..3613f39 Binary files /dev/null and b/test/visual_model_test/img/PH20240401000003_3_001938_2.jpg differ diff --git a/test/visual_model_test/img/PH20240511000638_1_094306_1.jpg b/test/visual_model_test/img/PH20240511000638_1_094306_1.jpg new file mode 100644 index 0000000..e9da016 Binary files /dev/null and b/test/visual_model_test/img/PH20240511000638_1_094306_1.jpg differ diff --git a/test/visual_model_test/img/PH20240511000648_4_094542_2.jpg b/test/visual_model_test/img/PH20240511000648_4_094542_2.jpg new file mode 100644 index 0000000..acd6bf0 Binary files /dev/null and b/test/visual_model_test/img/PH20240511000648_4_094542_2.jpg differ diff --git a/test/visual_model_test/visual_model_test.py b/test/visual_model_test/visual_model_test.py new file mode 100644 index 0000000..1104f22 --- /dev/null +++ b/test/visual_model_test/visual_model_test.py @@ -0,0 +1,67 @@ +# 可视化的模型对比测试 +import re +import time +from pprint import pprint + +from paddlenlp import Taskflow +from paddlenlp.utils.doc_parser import DocParser + + +def visual_model_test(task_path, test_img, schema): + img = re.split(r'[\\/]', test_img)[-1] + img_name = "" + img_type = "jpg" + last_dot_index = img.rfind(".") + if last_dot_index != -1: + img_name = img[:last_dot_index] + img_type = img[last_dot_index + 1:] + + # 默认模型 + ie = Taskflow("information_extraction", schema=schema, model="uie-x-base") + results = ie({"doc": test_img}) + pprint(results[0]) + DocParser.write_image_with_results( + test_img, + result=results[0], + save_path="./img_result/" + img_name + "_default." + img_type) + # 自己训练的模型 + my_ie = Taskflow("information_extraction", schema=schema, model="uie-x-base", task_path=task_path) + my_results = my_ie({"doc": test_img}) + pprint(my_results[0]) + DocParser.write_image_with_results( + test_img, + result=my_results[0], + save_path="./img_result/" + img_name + "_my." + img_type) + + +def main(model_type): + # 开始时间 + start_time = time.time() + + # 结算清单 + if model_type == "settlement": + task_path = "../../config/model/settlement_list_model" + test_img_path = "img/PH20240511000638_1_094306_1.jpg" + schema = ["姓名", "入院日期", "出院日期", "费用总额", "个人现金支付", "个人账户支付", "自费", "医保类型"] + elif model_type == "discharge": + task_path = "../../config/model/discharge_record_model" + test_img_path = "img/PH20240401000003_3_001938_2.jpg" + schema = ["医院", "科别", "姓名", "入院日期", "出院日期", "主治医生"] + elif model_type == "cost": + task_path = "../../config/model/cost_list_model" + test_img_path = "img/PH20240511000648_4_094542_2.jpg" + schema = ["姓名", "入院日期", "出院日期", "费用总额"] + else: + print("请输入正确的类型!") + return + visual_model_test(task_path, test_img_path, schema) + + # 结束时间 + end_time = time.time() + pprint(f"处理时长:{end_time - start_time}秒") + + +if __name__ == '__main__': + main("settlement") + # main("discharge") + # main("cost")