diff --git a/db/mysql.py b/db/mysql.py index 85ca264..9b37fdf 100644 --- a/db/mysql.py +++ b/db/mysql.py @@ -361,53 +361,8 @@ class ZxIeOcrerror(Base): cPhhd_id = Column(String(20), comment='拍一拍单据号') -class ZxIePhpjerror1(Base): - __tablename__ = 'zx_ie_phpjerror1' - - pk_phhd = Column(INTEGER(11), primary_key=True, comment='病案主键') - cphhd_id = Column(VARCHAR(20), index=True, comment='拍一拍单据号') - billdate = Column(DateTime, index=True) - cxm = Column(String(12), comment='姓名') - csfzh = Column(VARCHAR(20), index=True, comment='身份证号') - pk_yljg = Column(INTEGER(11), server_default=text("'0'"), comment='医院pk') - pk_yljg_ocr = Column(INTEGER(11), server_default=text("'0'"), comment='医院pk') - pk_ylks = Column(INTEGER(11), server_default=text("'0'"), comment='科室pk') - pk_ylks_ocr = Column(INTEGER(11), server_default=text("'0'"), comment='科室pk') - cdoctor = Column(VARCHAR(20), comment='医生') - cdoctor_ocr = Column(VARCHAR(20), comment='医生') - czyh = Column(VARCHAR(20), comment='住院号') - czyh_ocr = Column(VARCHAR(20), comment='住院号') - dzyrq = Column(DateTime, comment='入院日期') - dzyrq_ocr = Column(DateTime, comment='入院日期') - dcyrq = Column(DateTime) - dcyrq_ocr = Column(DateTime) - input_cxm = Column(String(20), comment='姓名核对') - input_cxm_ocr = Column(String(20), comment='姓名核对') - ffsylfy = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='发生医疗费用') - ffsylfy_ocr = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='发生医疗费用') - fgrzfje1 = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额1') - fgrzfje1_ocr = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额1') - fgezfje2 = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额2') - fgezfje2_ocr = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人支付金额2') - fgrzfje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人自费金额') - fgrzfje_ocr = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='个人自费金额') - fzfje = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='自付金额') - fzfje_ocr = Column(DECIMAL(18, 2), server_default=text("'0.00'"), comment='自付金额') - yb_type = Column(VARCHAR(10), comment='医保类别') - yb_type_ocr = Column(VARCHAR(20), comment='医保类别') - cjsd_id = Column(VARCHAR(30), comment='结算单号码') - cjsd_id_ocr = Column(VARCHAR(30), comment='结算单号码') - fage = Column(INTEGER(4), server_default=text("'0'"), comment='年龄') - fage_ocr = Column(INTEGER(4), server_default=text("'0'"), comment='年龄') - creator = Column(VARCHAR(30), index=True, comment='创建人') - creationtime = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='创建时间') - modifier = Column(VARCHAR(30), comment='最后修改人') - modifiedtime = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"), comment='最后修改时间') - cstatus = Column(CHAR(1), index=True, server_default=text("'0'"), comment='状态') - - -class ZxIePhpjerror2(Base): - __tablename__ = 'zx_ie_phpjerror2' +class ViewErrorReview(Base): + __tablename__ = 'view_error_review' pk_phhd = Column(INTEGER(11), primary_key=True, comment='病案主键') cphhd_id = Column(VARCHAR(20), index=True, comment='拍一拍单据号') diff --git a/docker-compose.yml b/docker-compose.yml index 5453658..3880ef1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ x-env: &template - image: fcb_photo_review:1.12.13 + image: fcb_photo_review:1.12.14 restart: always services: diff --git a/photo_review/photo_review_error_check.py b/photo_review/photo_review_error_check.py new file mode 100644 index 0000000..8c0f9da --- /dev/null +++ b/photo_review/photo_review_error_check.py @@ -0,0 +1,230 @@ +import json +import os +import sys +from datetime import date, timedelta +from decimal import Decimal +from io import BytesIO +from itertools import groupby + +import requests +from PIL import ImageFont, ImageDraw, Image +from sqlalchemy import update + +from db import MysqlSession +from db.mysql import ViewErrorReview, ZxPhhd, ZxPhrec, ZxIeResult, ZxIeSettlement, ZxIeDischarge, ZxIeCost +from ucloud import ufile +from util import image_util + + +def main(pk_phhd=None): + session = MysqlSession() + error_query = (session.query(ZxPhhd.pk_phhd, ZxPhhd.cXm, ViewErrorReview.pk_yljg, ViewErrorReview.pk_yljg_ocr, + ViewErrorReview.pk_ylks, ViewErrorReview.pk_ylks_ocr, ViewErrorReview.cdoctor, + ViewErrorReview.cdoctor_ocr, ViewErrorReview.czyh, ViewErrorReview.czyh_ocr, + ViewErrorReview.dzyrq, ViewErrorReview.dzyrq_ocr, ViewErrorReview.dcyrq, + ViewErrorReview.dcyrq_ocr, ViewErrorReview.input_cxm, ViewErrorReview.input_cxm_ocr, + ViewErrorReview.ffsylfy, ViewErrorReview.ffsylfy_ocr, ViewErrorReview.fgrzfje1, + ViewErrorReview.fgrzfje1_ocr, ViewErrorReview.fgezfje2, ViewErrorReview.fgezfje2_ocr, + ViewErrorReview.fgrzfje, ViewErrorReview.fgrzfje_ocr, ViewErrorReview.yb_type, + ViewErrorReview.yb_type_ocr, ViewErrorReview.cjsd_id, ViewErrorReview.cjsd_id_ocr, + ViewErrorReview.fage, ViewErrorReview.fage_ocr, ZxPhhd.problem_note) + .join(ZxPhhd, ViewErrorReview.pk_phhd == ZxPhhd.pk_phhd, isouter=True)) + if pk_phhd: + error_query = error_query.filter(ZxPhhd.pk_phhd == pk_phhd) + else: + today = date.today() + error_query = (error_query.filter(ZxPhhd.problem_note.is_(None)) + .filter(ViewErrorReview.creationtime >= today) + .filter(ViewErrorReview.creationtime < today + timedelta(days=1)) + .order_by(ViewErrorReview.creationtime.desc())) + error_review = error_query.limit(1).one_or_none() + if error_review is None: + print("没有需要检查的记录") + sys.exit() + + pk_phhd = error_review.pk_phhd + # 文件路径 + directory = f"./review_error_check/{pk_phhd}" + if not os.path.exists(directory): + os.makedirs(directory) + + json_result = { + "pk_phhd": pk_phhd, + "cXm": error_review.cXm + } + + settlement_query = session.query(ZxIeSettlement.pk_ie_settlement) + discharge_query = session.query(ZxIeDischarge.pk_ie_discharge) + cost_query = session.query(ZxIeCost.pk_ie_cost) + + if error_review.pk_yljg != error_review.pk_yljg_ocr: + json_result["医院pk_yljg"] = error_review.pk_yljg + json_result["pk_yljg_ocr"] = error_review.pk_yljg_ocr + discharge_query = discharge_query.add_columns(ZxIeDischarge.hospital, ZxIeDischarge.pk_yljg) + if error_review.pk_ylks != error_review.pk_ylks_ocr: + json_result["科室pk_ylks"] = error_review.pk_ylks + json_result["pk_ylks_ocr"] = error_review.pk_ylks_ocr + discharge_query = discharge_query.add_columns(ZxIeDischarge.department, ZxIeDischarge.pk_ylks) + if error_review.cdoctor != error_review.cdoctor_ocr: + json_result["医生cdoctor"] = error_review.cdoctor + json_result["cdoctor_ocr"] = error_review.cdoctor_ocr + discharge_query = discharge_query.add_column(ZxIeDischarge.doctor) + if error_review.czyh != error_review.czyh_ocr: + json_result["住院号czyh"] = error_review.czyh + json_result["czyh_ocr"] = error_review.czyh_ocr + settlement_query = settlement_query.add_column(ZxIeSettlement.admission_id) + discharge_query = discharge_query.add_column(ZxIeDischarge.admission_id) + if error_review.dzyrq != error_review.dzyrq_ocr: + json_result["入院日期dzyrq"] = error_review.dzyrq + json_result["dzyrq_ocr"] = error_review.dzyrq_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.admission_date_str, + ZxIeSettlement.admission_date) + discharge_query = discharge_query.add_columns(ZxIeDischarge.admission_date_str, ZxIeDischarge.admission_date) + cost_query = cost_query.add_columns(ZxIeCost.admission_date_str, ZxIeCost.admission_date) + if error_review.dcyrq != error_review.dcyrq_ocr: + json_result["出院日期dcyrq"] = error_review.dcyrq + json_result["dcyrq_ocr"] = error_review.dcyrq_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.discharge_date_str, + ZxIeSettlement.discharge_date) + discharge_query = discharge_query.add_columns(ZxIeDischarge.discharge_date_str, ZxIeDischarge.discharge_date) + cost_query = cost_query.add_columns(ZxIeCost.discharge_date_str, ZxIeCost.discharge_date) + if error_review.input_cxm != error_review.input_cxm_ocr: + json_result["姓名input_cxm"] = error_review.input_cxm + json_result["input_cxm_ocr"] = error_review.input_cxm_ocr + settlement_query = settlement_query.add_column(ZxIeSettlement.name) + discharge_query = discharge_query.add_column(ZxIeDischarge.name) + cost_query = cost_query.add_column(ZxIeCost.name) + if error_review.ffsylfy != error_review.ffsylfy_ocr: + json_result["费用总额ffsylfy"] = error_review.ffsylfy + json_result["ffsylfy_ocr"] = error_review.ffsylfy_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.medical_expenses_str, + ZxIeSettlement.medical_expenses) + cost_query = cost_query.add_columns(ZxIeCost.medical_expenses_str, ZxIeCost.medical_expenses) + if error_review.fgrzfje1 != error_review.fgrzfje1_ocr: + json_result["个人现金支付fgrzfje1"] = error_review.fgrzfje1 + json_result["fgrzfje1_ocr"] = error_review.fgrzfje1_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.personal_cash_payment_str, + ZxIeSettlement.personal_cash_payment) + if error_review.fgezfje2 != error_review.fgezfje2_ocr: + json_result["个人账户支付fgezfje2"] = error_review.fgezfje2 + json_result["fgezfje2_ocr"] = error_review.fgezfje2_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.personal_account_payment_str, + ZxIeSettlement.personal_account_payment) + if error_review.fgrzfje != error_review.fgrzfje_ocr: + json_result["个人自费fgrzfje"] = error_review.fgrzfje + json_result["fgrzfje_ocr"] = error_review.fgrzfje_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.personal_funded_amount_str, + ZxIeSettlement.personal_funded_amount) + if error_review.yb_type != error_review.yb_type_ocr: + json_result["医保类型yb_type"] = error_review.yb_type + json_result["yb_type_ocr"] = error_review.yb_type_ocr + settlement_query = settlement_query.add_columns(ZxIeSettlement.medical_insurance_type_str, + ZxIeSettlement.medical_insurance_type) + if error_review.cjsd_id != error_review.cjsd_id_ocr: + json_result["结算单号cjsd_id"] = error_review.cjsd_id + json_result["cjsd_id_ocr"] = error_review.cjsd_id_ocr + settlement_query = settlement_query.add_column(ZxIeSettlement.settlement_id) + if error_review.fage != error_review.fage_ocr: + json_result["年龄fage"] = error_review.fage + json_result["fage_ocr"] = error_review.fage_ocr + discharge_query = discharge_query.add_column(ZxIeDischarge.age) + + settlement = settlement_query.filter(ZxIeSettlement.pk_phhd == pk_phhd).one_or_none() + if settlement is not None: + json_result["settlement"] = settlement._asdict() + discharge = discharge_query.filter(ZxIeDischarge.pk_phhd == pk_phhd).one_or_none() + if discharge is not None: + json_result["discharge"] = discharge._asdict() + cost = cost_query.filter(ZxIeCost.pk_phhd == pk_phhd).one_or_none() + if cost is not None: + json_result["cost"] = cost._asdict() + + phrecs = session.query(ZxPhrec.pk_phrec, ZxPhrec.pk_phhd, ZxPhrec.cRectype, ZxPhrec.cfjaddress).filter( + ZxPhrec.pk_phhd == pk_phhd).all() + for phrec in phrecs: + img_name = phrec.cfjaddress + img_path = ufile.get_private_url(img_name) + + response = requests.get(img_path) + image = Image.open(BytesIO(response.content)).convert("RGB") + font_size = image.width * image.height / 200000 + font = ImageFont.truetype("./font/simfang.ttf", size=font_size) + + ie_result = session.query(ZxIeResult.id, ZxIeResult.content, ZxIeResult.rotation_angle, ZxIeResult.x_offset, + ZxIeResult.y_offset).filter(ZxIeResult.pk_phrec == phrec.pk_phrec).all() + if not ie_result: + no_ie_directory = f"{directory}/0" + if not os.path.exists(no_ie_directory): + os.makedirs(no_ie_directory) + image.save(f"{no_ie_directory}/{img_name}") + + for _, group_results in groupby(ie_result, key=lambda x: x.id): + draw = ImageDraw.Draw(image) + for ocr_item in group_results: + result = json.loads(ocr_item.content) + rotation_angle = ocr_item.rotation_angle + x_offset = ocr_item.x_offset + y_offset = ocr_item.y_offset + for key in result: + for value in result[key]: + box = value["bbox"][0] + + if rotation_angle: + box = image_util.invert_rotate_rectangle(box, (image.width / 2, image.height / 2), + rotation_angle) + if x_offset: + box[0] += x_offset + box[2] += x_offset + if y_offset: + box[1] += y_offset + box[3] += y_offset + + draw.rectangle(box, outline="red", width=2) # 绘制矩形 + draw.text((box[0], box[1] - font_size), key, fill="blue", font=font) # 在矩形上方绘制文本 + draw.text((box[0], box[3]), value["text"], fill="blue", font=font) # 在矩形下方绘制文本 + ie_directory = f"{directory}/{ocr_item.id}" + os.makedirs(ie_directory, exist_ok=True) + image.save(f"{ie_directory}/{img_name}") + session.close() + + # 自定义JSON处理器 + def default(obj): + if isinstance(obj, Decimal): + return float(obj) + if isinstance(obj, date): + return obj.strftime("%Y-%m-%d") + + with open(f"{directory}/result.json", "w", encoding="utf-8") as json_file: + json.dump(json_result, json_file, indent=4, ensure_ascii=False, default=default) + + return pk_phhd + + +if __name__ == '__main__': + pk_phhd = main() + while True: + check_finish = input(f"{pk_phhd}是否完成(是/否):") + if check_finish == "是": + """ + 错误描述的写法: + 1. 查看result.json,以含中文的key中的中文为现在的key + 2. 为方便输入,key之后跟中文冒号 + 3. 冒号之后写错误原因,原因最好是固定的几种写法 + 4. 可以在原因后跟中文括号,并在括号中进行补充说明 + 5. 写完错误原因以中文分号结尾,最后一个可以不加分号 + 举例: + 错误描述:医院:未知错误;科室:还是未知错误(补充说明) + """ + error_descript = input("错误描述:") + break + elif check_finish == "否": + sys.exit() + else: + print("无效输入!请输入“是”或者“否”") + + session = MysqlSession() + update_error = update(ZxPhhd).where(ZxPhhd.pk_phhd == pk_phhd).values(problem_note=error_descript) + session.execute(update_error) + session.commit() + session.close() + print(f"【{pk_phhd}】错误分析已完成。错误描述:{error_descript}") diff --git a/photo_review/photo_review_error_report.py b/photo_review/photo_review_error_report.py new file mode 100644 index 0000000..b14a46b --- /dev/null +++ b/photo_review/photo_review_error_report.py @@ -0,0 +1,99 @@ +import json +from collections import defaultdict +from datetime import date, timedelta + +from sqlalchemy.sql.functions import count + +from db import MysqlSession +from db.mysql import ZxPhhd, ViewErrorReview +from util import util + + +def handle_reason(reason): + if "(" in reason: + reason = reason.split("(")[0] + return reason + + +if __name__ == '__main__': + today = date.today() + session = MysqlSession() + error_reviews_count = (session.query(count()) + .filter(ViewErrorReview.creationtime >= today) + .filter(ViewErrorReview.creationtime < today + timedelta(days=1)) + .scalar()) + error_reviews = (session.query(ZxPhhd.problem_note, ViewErrorReview.pk_phhd) + .join(ZxPhhd, ViewErrorReview.pk_phhd == ZxPhhd.pk_phhd, isouter=True) + .filter(ZxPhhd.problem_note.is_not(None)) + .filter(ViewErrorReview.creationtime >= today) + .filter(ViewErrorReview.creationtime < today + timedelta(days=1)) + .all()) + session.close() + + result = {f"{today}涂抹错误图片总数": error_reviews_count} + hospital_result = defaultdict(int) + department_result = defaultdict(int) + doctor_result = defaultdict(int) + admission_id_result = defaultdict(int) + admission_date_result = defaultdict(int) + discharge_date_result = defaultdict(int) + name_result = defaultdict(int) + medical_expenses_result = defaultdict(int) + personal_cash_payment_result = defaultdict(int) + personal_account_payment_result = defaultdict(int) + personal_funded_amount_result = defaultdict(int) + medical_insurance_type_result = defaultdict(int) + settlement_id_result = defaultdict(int) + age_result = defaultdict(int) + for error_review in error_reviews: + columns = error_review.problem_note.split(";") + for column in columns: + key, value = column.split(":") + if key == "医院": + hospital_result[handle_reason(value)] += 1 + elif key == "科室": + department_result[handle_reason(value)] += 1 + elif key == "医生": + doctor_result[handle_reason(value)] += 1 + elif key == "住院号": + admission_id_result[handle_reason(value)] += 1 + elif key == "入院日期": + admission_date_result[handle_reason(value)] += 1 + elif key == "出院日期": + discharge_date_result[handle_reason(value)] += 1 + elif key == "姓名": + name_result[handle_reason(value)] += 1 + elif key == "费用总额": + medical_expenses_result[handle_reason(value)] += 1 + elif key == "个人现金支付": + personal_cash_payment_result[handle_reason(value)] += 1 + elif key == "个人账户支付": + personal_account_payment_result[handle_reason(value)] += 1 + elif key == "个人自费": + personal_funded_amount_result[handle_reason(value)] += 1 + elif key == "医保类别": + medical_insurance_type_result[handle_reason(value)] += 1 + elif key == "结算单号": + settlement_id_result[handle_reason(value)] += 1 + elif key == "年龄": + age_result[handle_reason(value)] += 1 + result["医院"] = hospital_result + result["科室"] = department_result + result["主治医生"] = doctor_result + result["住院号"] = admission_id_result + result["住院日期"] = admission_date_result + result["出院日期"] = discharge_date_result + result["患者姓名"] = name_result + result["费用总额"] = medical_expenses_result + result["个人现金支付"] = personal_cash_payment_result + result["个人账户支付"] = personal_account_payment_result + result["个人自费"] = personal_funded_amount_result + result["医保类型"] = medical_insurance_type_result + result["结算单号"] = settlement_id_result + result["年龄"] = age_result + + print(result) + with open("photo_review_error_report.txt", 'w', encoding='utf-8') as file: + file.write(json.dumps(result, indent=4, ensure_ascii=False)) + file.write(util.get_default_datetime()) + print("结果已保存。")