123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import json
- import os
- import random
- import time
- from multiprocessing import Process, Queue
- from shutil import move
- from sqlalchemy import create_engine, and_,func
- from sqlalchemy.orm import sessionmaker
- from core.config import settings
- from models.marktask import *
- from models.paper import *
- from models.problem import *
- from utils.imgtool import crop_img_local, crop_img_remote
- from utils.fileuploader import ossfile_uploader
- from .recpaper import RecPaper
- from utils.cv2img import get_std_points,rec_ans
- engine = create_engine(settings.SYNC_MYSQL_URI)
- session = sessionmaker(bind=engine)
- def upload_simgs(simgs):
- """
- """
- urls = []
- for img in simgs:
- ossfile = os.path.split(img)[-1]
- url = ossfile_uploader.upload_from_file(img,ossfile,{"Content-Type":"image/png"})
- urls.append(url)
- return urls
- def get_marktask(task_id):
- """
- """
- dbsession = session()
- task_id = int(task_id)
- task = dbsession.query(MarkTask).get(task_id)
- dbsession.close()
- if task:
- return task
- return None
- def get_paper(pid):
- """
- """
- dbsession = session()
- pid = int(pid)
- paper = dbsession.query(Paper).get(pid)
- dbsession.close()
- if paper:
- return paper
- return None
- def get_paper_pieces(pid):
- """
- """
- dbsession = session()
- pid = int(pid)
- ques = dbsession.query(PaperQuestion).filter(and_(PaperQuestion.pid == pid,PaperQuestion.usage.in_([1,2]))).all()
- dbsession.close()
- if ques:
- return ques
- return None
- def get_student_marktask(task_id, sno):
- """
- """
- dbsession = session()
- task_id = int(task_id)
- smarktask = dbsession.query(StudentMarkTask).filter(
- and_(StudentMarkTask.task_id == task_id, StudentMarkTask.student_sno == sno)).scalar()
- dbsession.close()
- if smarktask:
- return smarktask
- return None
- def update_student_marktask(task_id, sno, imgs):
- """
- """
- dbsession = session()
- task = dbsession.query(StudentMarkTask).filter(StudentMarkTask.task_id==task_id)\
- .filter(StudentMarkTask.student_sno==sno).one()
- task.pimgs = json.dumps(imgs)
- dbsession.commit()
- dbsession.close()
- def get_student_answer(student_task_id,student_id,qid):
- """
- """
- dbsession = session()
- student_answer = dbsession.query(StudentAnswer).filter(
- and_(
- StudentAnswer.student_task_id==student_task_id,
- StudentAnswer.student_id==student_id,
- StudentAnswer.qid==qid,
- )).scalar()
- dbsession.close()
- if student_answer:
- return student_answer
- return None
- def create_student_answer(**info):
- """
- """
- dbsession = session()
- answer = StudentAnswer(**info)
- dbsession.add(answer)
- dbsession.commit()
- dbsession.refresh(answer)
- dbsession.close()
- return answer
- def update_student_answer(said,info):
- """更新学生答卷
- """
- dbsession = session()
- dbsession.query(StudentAnswer).filter(StudentAnswer.id==said).update(info)
- dbsession.commit()
- dbsession.close()
- def update_task(tid,info):
- """更新阅卷任务
- """
- dbsession = session()
- dbsession.query(MarkTask).filter(MarkTask.id==tid).update(info)
- dbsession.commit()
- dbsession.close()
- def update_student_marktask_status(said,info):
- """更新学生任务
- """
- dbsession = session()
- dbsession.query(StudentMarkTask).filter(StudentMarkTask.id==said).update(info)
- dbsession.commit()
- dbsession.close()
- def get_uploaded_amount(task_id):
- """获取已上传数量
- """
- dbsession = session()
- allsmt = dbsession.query(func.count(StudentMarkTask.id)).filter(StudentMarkTask.status==2).scalar()
- dbsession.close()
- return allsmt
- def update_class_error_questions(task_id,qid,answer,error_count,minus_answer):
- """更新班级错题记录
- """
- dbsession = session()
- db_class_error = dbsession.query(ClassErrorQuestion).filter(and_(ClassErrorQuestion.task_id==task_id,ClassErrorQuestion.qid==qid)).one()
- if db_class_error:
- #单题班级错题率
- error_count = db_class_error.error_count + error_count
- error_ratio = round(error_count / db_class_error.student_count * 100, 2)
- #错题分布
- answer_dist = json.loads(db_class_error.answer_dist) if db_class_error.answer_dist else {}
- if not answer_dist:
- answer_dist[answer] = 1
- else:
- answer_dist[answer] = answer_dist.get(answer, 0) + 1
- if minus_answer and answer_dist.get(minus_answer):
- answer_dist[minus_answer] = answer_dist[minus_answer] - 1
- db_class_error.error_count = error_count
- db_class_error.error_ratio = error_ratio
- db_class_error.answer_dist = json.dumps(answer_dist)
- dbsession.add(db_class_error)
- dbsession.commit()
- dbsession.refresh(db_class_error)
- dbsession.close()
- def update_student_error_questions(task,smarktask,error_count):
- """更新学生错题统计
- """
- task_id = task.id
- student_task_id = smarktask.id
- student_id = smarktask.student_id
- dbsession = session()
- db_student_error = dbsession.query(StudentErrorQuestion).filter(
- and_(
- StudentErrorQuestion.task_id==task_id,
- StudentErrorQuestion.student_task_id==student_task_id,
- StudentErrorQuestion.student_id==student_id
- )).one_or_none()
- if db_student_error:
- work_error_count = db_student_error.work_error_count + error_count
- total_errors = work_error_count
- error_ratio = round(total_errors/db_student_error.total_questions,2)*100
- db_student_error.work_error_count = work_error_count
- db_student_error.total_errors = total_errors
- db_student_error.error_ratio = error_ratio
- dbsession.add(db_student_error)
- dbsession.commit()
- dbsession.refresh(db_student_error)
- dbsession.close()
- def produce_papers(q):
- """
- """
- simgs = []
- while True:
- if not os.path.exists(settings.PAPERS_PATH):
- os.makedirs(settings.PAPERS_PATH)
- imglist = os.listdir(settings.PAPERS_PATH)
- imglist.sort()
- for pimg in imglist:
- if pimg.startswith("T"):
- pfile = os.path.join(settings.PAPERS_PATH, pimg)
- if os.path.isdir(pfile):
- ppimgs = os.listdir(pfile)
- if ppimgs:
- ppimgs.sort()
- task_id = os.path.split(pfile)[-1].split("-")[0].lstrip("T")
- task = get_marktask(task_id)
- if task:
- pages = task.pages
- for ppimg in ppimgs:
- src = os.path.join(pfile, ppimg)
- if os.path.isfile(src):
- workspace = os.path.join(pfile, "workspace")
- if not os.path.exists(workspace):
- os.makedirs(workspace)
- target = os.path.join(workspace, ppimg)
- move(src, target)
- simgs.append(target)
- if len(simgs) < pages:
- continue
- else:
- q.put(simgs)
- simgs = []
- time.sleep(0.1)
- def rec_papers(simgs, task):
- """
- """
- task_id = task.id
- pid = task.pid
- ans_points = json.loads(task.ans_points)
- # 识别考号和答案
- ans_img = simgs[0]
- std_points = get_std_points(ans_img)
- std_x = std_points[0]["x"]
- std_y = std_points[0]["y"]
- x = ans_points["x"] + std_x
- y = ans_points["y"] + std_y
- w = ans_points["w"]
- h = ans_points["h"]
- cut_point = (x, y, x + w, y + h)
- ans_img_card = crop_img_local(ans_img, cut_point)
- # 别考号和客观题
- qno_list = []
- # 获取标准切割的试题
- std_ques = get_paper_pieces(pid)
- for que in std_ques:
- if que.qtype in ["单选题","多选题"]:
- qno_list.append(que.qno)
- sno = random.choice(["010001","010002","010003","010004","010005"])
- # 单个学生阅卷任务
- smarktask = get_student_marktask(task_id, sno)
- if smarktask:
- pimgs = upload_simgs(simgs)
- update_student_marktask_status(smarktask.id,{"status":1,"pimgs":pimgs})
- # 生产学生作答库
- for que in std_ques:
- page = que.page
- qno = que.qno
- sqno = que.sqno
- qtype = que.qtype
- points = que.points
- std_ans = que.answer
- std_score = que.score
-
- marked_score = 0
- incorrect = 0
- status = 0
- answer = ""
- if qtype in ["单选题","多选题"]:
- std_ans_points = que.std_points
- answer = rec_ans(ans_img_card,std_ans_points)
- print(qno,answer,99999999999999)
- status = 1
- if answer != std_ans:
- marked_score = 0
- incorrect = 1
- else:
- marked_score = std_score
- ans_imgs = []
- for point in points:
- x = point["x"] + std_x
- y = point["y"] + std_y
- w = point["w"]
- h = point["h"]
- cut_point = (x, y, x + w, y + h)
- url = crop_img_remote(simgs[page], cut_point, qno)
- ans_imgs.append(url)
- answerdict = {
- "student_id": smarktask.student_id,
- "student_sno": smarktask.student_sno,
- "student_name": smarktask.student_name,
- "class_id": task.class_id,
- "task_id": task_id,
- "task_name": task.name,
- "student_task_id": smarktask.id,
- "pid": pid,
- "pno": smarktask.pno,
- "pimgs": smarktask.pimgs,
- "pname": smarktask.pname,
- "qimg": ans_imgs[0],
- "qtype": qtype,
- "mtype": smarktask.mtype,
- "qno": qno,
- "sqno": sqno,
- "answer": answer,
- "score": que.score,
- "qid": que.id,
- "stem": que.stem,
- "score": std_score,
- "std_answer": std_ans,
- "status": status,
- "incorrect": incorrect,
- "marked_score": marked_score,
- "creator_id": 1,
- "creator_name": "admin",
- "editor_id": 1,
- "editor_name": "admin",
- "school_name": smarktask.school_name,
- "grade_name": smarktask.grade_name,
- "class_name": smarktask.class_name
- }
- error_count = 0
- minus_answer = ""
- student_error_count = 0
- student_answer = get_student_answer(smarktask.id,smarktask.student_id,que.id)
- if not student_answer:
- student_answer = create_student_answer(**answerdict)
- if student_answer.incorrect:
- error_count += 1
- student_error_count += 1
- else:
- if student_answer.incorrect != incorrect:
- if student_answer.incorrect:
- if error_count:
- error_count += -1
- else:
- error_count = 0
- #学生错题
- if student_error_count:
- student_error_count += -1
- else:
- student_error_count = 0
- else:
- error_count += 1
- student_error_count += 1
- if qtype in ["单选题","多选题"]:
- if student_answer.answer != answer:
- minus_answer = student_answer.answer
- update_student_answer(student_answer.id,answerdict)
- if qtype in ["单选题","多选题"]:
- #更新班级错题
- update_class_error_questions(task_id,que.id,answer,error_count,minus_answer)
- #更新学生错题
- update_student_error_questions(task,smarktask,student_error_count)
- update_student_marktask_status(smarktask.id,{"status":2})
- uploaded_count = get_uploaded_amount(task_id)
- update_task(task_id,{"uploaded_amount":uploaded_count})
- for img in simgs:
- os.remove(img)
- def consumer_papers(q):
- """
- """
- simgs = []
- while True:
- simgs = q.get()
- if simgs:
- print(f"start consumer simgs:{simgs}")
- pfile = simgs[0]
- task_id = pfile.split("workspace")[0].split("-")[0].split("/")[-1].lstrip("T")
- task = get_marktask(task_id)
- if task:
- rec_papers(simgs, task)
- time.sleep(0.1)
- if __name__ == "__main__":
- q = Queue()
- p1 = Process(target=produce_papers, args=(q,))
- p1.start()
- for i in range(4):
- p2 = Process(target=consumer_papers, args=(q,))
- p2.start()
|