ftgenerator.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. from generator import generator
  2. """
  3. 高校整卷数据生成器
  4. """
  5. from generator import generator
  6. import config
  7. import pandas as pd
  8. import json
  9. import numpy as np
  10. import random
  11. import commonhandle
  12. import openpyxl
  13. import os
  14. from ftmarkingcloudInf import ftmarkingcloudInf
  15. from imagebuilder import imageBuilder
  16. import logger
  17. class ftgenerator(generator):
  18. def __init__(self):
  19. self.courseLst = []
  20. course_content = config.course.split(",")
  21. self.questionLst=[]
  22. self.dataoutputpath=str(config.examId)
  23. if not os.path.exists(self.dataoutputpath):
  24. os.makedirs(self.dataoutputpath)
  25. for courses in course_content:
  26. if len(courses.split("#")) < 3:
  27. raise Exception("课程参数未配置齐全,请检查")
  28. self.courseLst.append(
  29. {"code": courses.split("#")[0], "name": courses.split("#")[1], "imagenum": int(courses.split("#")[2])})
  30. object_num=config.singlechoice_num+config.multichoice_num+config.trueorfalse_num
  31. if object_num==0 and config.subjective_num==0:
  32. raise Exception("总题目数量为0,请保证至少含有一道客观题或者一道主观题")
  33. self.choice =[]
  34. for i in range(int(config.choice_len)):
  35. self.choice.append(chr(65+i))
  36. self.single_choice_order=[]
  37. self.multi_choice_order=[]
  38. self.trueorfalse_order=[]
  39. order=1
  40. for idx in range(int(config.singlechoice_num)):
  41. self.single_choice_order.append(order)
  42. order=order+1
  43. for idx in range(int(config.multichoice_num)):
  44. self.multi_choice_order.append(order)
  45. order=order+1
  46. for idx in range(int(config.trueorfalse_num)):
  47. self.trueorfalse_order.append(order)
  48. order=order+1
  49. self.initTeacherandClassandColleage()
  50. self.inf=ftmarkingcloudInf()
  51. self.inf.selectExam()
  52. def initTeacherandClassandColleage(self):
  53. """
  54. 生成学院老师班级,只要有一个为空都直接抛异常
  55. 总共有多少老师,每个学院下有多少班级,班级由老师平均分配
  56. """
  57. colleage_prefix="学院_"
  58. teacher_prefix="教师_"
  59. class_prefix="班级_"
  60. self.colleageLst={}
  61. if config.teacher_num!=0 and config.colleage_num!=0 and config.classundercolleage_num!=0:
  62. teacher_postfix = range(1, config.teacher_num + 1)
  63. for i in range(1,(config.colleage_num+1)):
  64. colleage_name=colleage_prefix+str(i)
  65. self.colleageLst[colleage_name]={}
  66. for j in range(1,config.classundercolleage_num+1):
  67. classname=colleage_name+"_"+class_prefix+str(j)
  68. postfix=random.choice(teacher_postfix)
  69. self.colleageLst[colleage_name][classname]=teacher_prefix+str(postfix)
  70. def studentgenerator(self):
  71. student_temp_path = self.dataoutputpath + os.sep + "temp"
  72. if os.path.exists(student_temp_path + os.sep + "student_temp.xlsx"):
  73. os.remove(student_temp_path + os.sep + "student_temp.xlsx")
  74. if os.path.exists(student_temp_path + os.sep + "upload.json"):
  75. os.remove(student_temp_path + os.sep + "upload.json")
  76. self.student_name_prefix = "张大_"
  77. self.org_name_prefix = "数据中心_"
  78. self.signtable_prefix = 19000000
  79. self.student_code_prefix = 19000000
  80. self.identity_num_prefix = 19000000
  81. self.batch_prefix="A"
  82. student_template_file = openpyxl.load_workbook("template/ft/考生数据导入模板.xlsx")
  83. student_sheet = student_template_file.active
  84. start_row = 3
  85. for idx in range(1,int(config.studentnum)+1):
  86. # 随机获取课程
  87. courses = random.choice(self.courseLst)
  88. if config.signtable_num!=0:
  89. signtable=self.signtable_prefix+random.choice(range(1,config.signtable_num+1))
  90. else:
  91. signtable=""
  92. #student_sheet.cell(start_row, 1, self.org_name_prefix +str(random.choice(range(1,config.org_num))))
  93. student_sheet.cell(start_row, 1, courses["code"])
  94. student_sheet.cell(start_row, 2, courses["name"])
  95. student_sheet.cell(start_row, 3, self.identity_num_prefix + idx)
  96. student_sheet.cell(start_row, 4, self.student_code_prefix + idx)
  97. student_sheet.cell(start_row, 5, self.student_name_prefix + str(idx))
  98. student_sheet.cell(start_row, 6, signtable)
  99. student_sheet.cell(start_row, 7, self.org_name_prefix+str(random.choice(range(1,config.org_num+1))))
  100. student_sheet.cell(start_row, 8, "")
  101. student_sheet.cell(start_row, 9, "")
  102. student_sheet.cell(start_row, 10, "")
  103. student_sheet.cell(start_row, 11, "")
  104. if self.colleageLst:
  105. colleage_name=random.choice(list(self.colleageLst.keys()))
  106. class_name=random.choice(list(self.colleageLst[colleage_name].keys()))
  107. teachername=self.colleageLst[colleage_name][class_name]
  108. else:
  109. colleage_name=""
  110. class_name=""
  111. teachername=""
  112. student_sheet.cell(start_row, 12, colleage_name)
  113. student_sheet.cell(start_row, 13, class_name)
  114. student_sheet.cell(start_row, 14, teachername)
  115. student_sheet.cell(start_row, 15, "")
  116. start_row=start_row+1
  117. student_template_file.save(self.dataoutputpath+os.sep+"student.xlsx")
  118. def papergenerator(self):
  119. #生成object导入文件
  120. object_template_file=openpyxl.load_workbook("template/ft/客观题导入模板.xlsx")
  121. object_sheet=object_template_file.active
  122. start_row = 3
  123. for course in self.courseLst:
  124. main_number=1
  125. sub_number=1
  126. for i in range(1,config.singlechoice_num+1):
  127. object_sheet.cell(start_row, 1, course["code"])
  128. object_sheet.cell(start_row, 2, course["name"])
  129. object_sheet.cell(start_row, 4, "第%d大题"%(main_number))
  130. object_sheet.cell(start_row, 5, main_number)
  131. object_sheet.cell(start_row, 6, sub_number)
  132. object_sheet.cell(start_row, 7, random.choice(self.choice))
  133. object_sheet.cell(start_row, 8, config.question_point)
  134. sub_number=sub_number+1
  135. start_row=start_row+1
  136. main_number = main_number + 1
  137. sub_number=1
  138. for i in range(1,config.multichoice_num+1):
  139. object_sheet.cell(start_row, 1, course["code"])
  140. object_sheet.cell(start_row, 2, course["name"])
  141. object_sheet.cell(start_row, 4, "第%d大题"%(main_number))
  142. object_sheet.cell(start_row, 5, main_number)
  143. object_sheet.cell(start_row, 6, sub_number)
  144. #生成随机答案数量
  145. question_num=random.choice(range(1,len(self.choice)+1))
  146. righanswer=random.sample(self.choice,question_num)
  147. righanswer.sort()
  148. object_sheet.cell(start_row, 7, "".join(righanswer))
  149. object_sheet.cell(start_row, 8, config.question_point)
  150. sub_number = sub_number + 1
  151. start_row=start_row+1
  152. main_number=main_number+1
  153. sub_number = 1
  154. for i in range(1, config.trueorfalse_num + 1):
  155. object_sheet.cell(start_row, 1, course["code"])
  156. object_sheet.cell(start_row, 2, course["name"])
  157. object_sheet.cell(start_row, 4, "第%d大题" % (main_number))
  158. object_sheet.cell(start_row, 5, main_number)
  159. object_sheet.cell(start_row, 6, sub_number)
  160. # 生成随机答案数量
  161. object_sheet.cell(start_row, 7, random.choice(["A","B"]))
  162. object_sheet.cell(start_row, 8, config.question_point)
  163. sub_number = sub_number + 1
  164. start_row = start_row + 1
  165. object_template_file.save(self.dataoutputpath+os.sep+"object.xlsx")
  166. #生成主观题数据
  167. subject_template_file = openpyxl.load_workbook("template/ft/主观题导入模板.xlsx")
  168. subject_sheet = subject_template_file.active
  169. start_row = 3
  170. for course in self.courseLst:
  171. main_number = 1
  172. sub_number = 1
  173. for i in range(1, config.subjective_num + 1):
  174. subject_sheet.cell(start_row, 1, course["code"])
  175. subject_sheet.cell(start_row, 2, course["name"])
  176. subject_sheet.cell(start_row, 3, "第%d大题" % (main_number))
  177. subject_sheet.cell(start_row, 4, main_number)
  178. subject_sheet.cell(start_row, 5, sub_number)
  179. subject_sheet.cell(start_row, 6, config.question_point)
  180. subject_sheet.cell(start_row, 7, config.interval_score)
  181. subject_sheet.cell(start_row, 8, main_number)
  182. #图片预先按照subnumber顺序进行填入
  183. subject_sheet.cell(start_row, 9, main_number)
  184. main_number = main_number+1
  185. sub_number = sub_number + 1
  186. start_row = start_row + 1
  187. subject_template_file.save(self.dataoutputpath+os.sep+"subjective.xlsx")
  188. def importData(self):
  189. """
  190. 导入数据
  191. """
  192. print("start to import student data")
  193. self.inf.importStudent()
  194. print("start to import subjective data")
  195. self.inf.importSubjectivePaper()
  196. print("start to import objective data")
  197. self.inf.importObjectivePaper()
  198. def addMaker(self):
  199. for course in self.courseLst:
  200. count=input("请输入要创建的评卷员数量:")
  201. self.inf.batchcreateMarker(count,course["code"])
  202. def filterManual(self,line):
  203. if line["准考证号"] in list(self.nomauallst.values):
  204. line["maual"]=False
  205. else:
  206. line["maual"]=True
  207. return line
  208. def imagegenerator(self):
  209. """
  210. 生成签到表图片和学生作答图片及裁切图
  211. 签到表路径{examId}/{签到表编号}/1
  212. .jpg
  213. """
  214. #读取临时文件数据
  215. student_temp_path = self.dataoutputpath + os.sep + "temp"
  216. student_data_frame=pd.read_excel(student_temp_path+os.sep+"student_temp.xlsx")
  217. student_data_frame["课程代码"] = student_data_frame["课程代码"].astype('str')
  218. student_data_frame["准考证号"] = student_data_frame["准考证号"].astype('str')
  219. student_data_frame["学号"] = student_data_frame["学号"].astype('str')
  220. student_data_frame["签到表编号"] = student_data_frame["签到表编号"].astype('str')
  221. student_data_signtable_group = student_data_frame.groupby("签到表编号")
  222. commonhandle.generateSignTable(student_data_frame,student_data_signtable_group)
  223. with open(student_temp_path+os.sep+"upload.json", 'r', encoding='utf8')as fp:
  224. json_data = json.load(fp)
  225. for key,student_data in student_data_frame.iterrows():
  226. if not student_data["absent"]:
  227. #开始生成文件
  228. course_code=student_data["课程代码"]
  229. for course in self.courseLst:
  230. if str(course_code) == str(course["code"]):
  231. sheet_num = course["imagenum"]
  232. break
  233. # checkstudent获取学生的信息
  234. student_check_data = self.inf.queryStudent(student_data["准考证号"])
  235. print(student_check_data)
  236. sheet_path = str(config.examId) + os.sep + "image" + os.sep + "sheet" + os.sep + str(config.examId) + os.sep+ str(
  237. student_check_data["examNumber"][-3:])
  238. slice_path = str(config.examId) + os.sep + "image" + os.sep + "slice" + os.sep + str(config.examId) + os.sep + str(
  239. student_check_data["secrectNumber"][-3:])
  240. if not os.path.exists(sheet_path):
  241. os.makedirs(sheet_path)
  242. if not os.path.exists(slice_path):
  243. os.makedirs(slice_path)
  244. used_num = 1
  245. object_answerdata=json_data[student_data["准考证号"]]["objectanswer"]
  246. subject_answer_List=json_data[student_data["准考证号"]]["subject_answer"]
  247. if object_answerdata:
  248. first_image = imageBuilder(int(config.image_width), int(config.image_length),
  249. color=(255, 255, 255, 255))
  250. first_image.draw_text(200, 500, object_answerdata)
  251. image_path = sheet_path + os.sep + student_check_data["examNumber"] + "-" + str(used_num) + ".jpg"
  252. first_image.saveimage(image_path)
  253. used_num = used_num + 1
  254. unused_num = sheet_num - used_num + 1
  255. sheet_list = []
  256. sheet_list_path=[]
  257. for i in range(1, unused_num + 1):
  258. image = imageBuilder(int(config.image_width), int(config.image_length),
  259. color=(255, 255, 255, 255))
  260. image_path = sheet_path + os.sep + student_check_data["examNumber"] + "-" + str(
  261. used_num) + ".jpg"
  262. used_num = used_num + 1
  263. sheet_list.append(image)
  264. sheet_list_path.append(image_path)
  265. if len(subject_answer_List) != 0:
  266. # 裁切图数量
  267. slice_num = len(subject_answer_List)
  268. slice_index = 1
  269. data_group = np.array_split(range(slice_num), unused_num)
  270. image_index = 0
  271. for split_data in data_group:
  272. index_data = 0
  273. image = sheet_list[image_index]
  274. image.draw_text(0, 50,
  275. student_check_data["secrectNumber"])
  276. if len(split_data)>0:
  277. for split_single in split_data:
  278. # print("font pos:",config.image_length//len(split_data)*index_data+50,subject_answer_List[split_single])
  279. #
  280. image.draw_text(200, int(config.image_length) // len(split_data) * index_data + 50,
  281. subject_answer_List[split_single])
  282. # 生成slice截图
  283. split_image = image.splitImage(
  284. (0, int(config.image_length) // len(split_data) * index_data,
  285. 2200, int(config.image_length) // len(split_data) * (
  286. index_data + 1) - 50))
  287. split_image_path = slice_path + os.sep + student_check_data["secrectNumber"] + "-" + str(
  288. slice_index) + ".jpg"
  289. split_image.save(split_image_path)
  290. slice_index = slice_index + 1
  291. index_data = index_data + 1
  292. else:
  293. image.draw_text(200, 50,
  294. str(student_check_data["examNumber"])+"补充"+str(image_index))
  295. split_image = image.splitImage(
  296. (0, 0,
  297. 2200, int(config.image_length)))
  298. split_image_path = slice_path + os.sep + student_check_data["secrectNumber"] + "-" + str(
  299. slice_index) + ".jpg"
  300. split_image.save(split_image_path)
  301. slice_index = slice_index + 1
  302. index_data = index_data + 1
  303. image.saveimage(sheet_list_path[image_index])
  304. image_index = image_index + 1
  305. def filterabsent(self,line):
  306. if line["准考证号"] in list(self.noabsentLst.values):
  307. line["absent"] = False
  308. else:
  309. line["absent"] = True
  310. return line
  311. def uploadstudent(self):
  312. """
  313. 生成考生相关信息并上传
  314. """
  315. student_temp_path=self.dataoutputpath + os.sep + "temp"
  316. if not os.path.exists(student_temp_path):
  317. os.makedirs(student_temp_path)
  318. if os.path.exists(student_temp_path+os.sep+"student_temp.xlsx"):
  319. student_data_frame=pd.read_excel(student_temp_path+os.sep+"student_temp.xlsx")
  320. else:
  321. student_data_frame = pd.read_excel(self.dataoutputpath + os.sep + "student.xlsx", header=1)
  322. student_data_frame["课程代码"] = student_data_frame["课程代码"].astype('str')
  323. student_data_frame["准考证号"] = student_data_frame["准考证号"].astype('str')
  324. student_data_frame["学号"] = student_data_frame["学号"].astype('str')
  325. student_data_frame["签到表编号"] = student_data_frame["签到表编号"].astype('str')
  326. #根据
  327. student_absent_frame = student_data_frame.sample(
  328. int(len(student_data_frame) * (100 - int(config.absentper)) / 100))
  329. self.noabsentLst = student_absent_frame["准考证号"]
  330. student_data_frame = student_data_frame.apply(self.filterabsent,axis=1)
  331. #从中随机出manual
  332. student_maual_frame = student_absent_frame.sample(
  333. int(len(student_absent_frame) * (100 - int(config.manualper)) / 100))
  334. self.nomauallst = student_maual_frame["准考证号"]
  335. student_data_frame = student_data_frame.apply(self.filterManual, axis=1)
  336. #存储到temp文件夹下
  337. student_data_frame.to_excel(student_temp_path+os.sep+"student_temp.xlsx",index=False)
  338. #取出题目信息
  339. object_data_frame = pd.read_excel(self.dataoutputpath + os.sep + "object.xlsx", header=1)
  340. object_data_frame["科目代码"] = object_data_frame["科目代码"].astype('str')
  341. object_group = object_data_frame.groupby("科目代码")
  342. subject_data_frame = pd.read_excel(self.dataoutputpath + os.sep + "subjective.xlsx", header=1)
  343. subject_data_frame["科目代码"] = subject_data_frame["科目代码"].astype('str')
  344. subbject_group = subject_data_frame.groupby("科目代码")
  345. uploadList={}
  346. for key, student_data in student_data_frame.iterrows():
  347. if not student_data["absent"]:
  348. rightper = random.choice(range(101))
  349. course_code = student_data["课程代码"]
  350. for course in self.courseLst:
  351. if str(course_code) == str(course["code"]):
  352. sheet_num = course["imagenum"]
  353. break
  354. # 生成客观题作答信息
  355. if str(course_code) in object_group.groups:
  356. object_course_data = object_group.get_group(str(course_code))
  357. object_answerdata=commonhandle.generateObjectAnswer(rightper,student_data,object_course_data,self.single_choice_order,self.multi_choice_order,self.choice)
  358. else:
  359. object_answerdata=""
  360. if str(course_code) in subbject_group.groups:
  361. subject_course_data = subbject_group.get_group(str(course_code))
  362. subject_answer_List = commonhandle.generateSubjectAnswer(student_data,subject_course_data)
  363. else:
  364. subject_answer_List=[]
  365. uploadList[student_data["准考证号"]] = {"objectanswer": object_answerdata,
  366. "subject_answer": subject_answer_List}
  367. student_upload_data = {
  368. "examNumber": student_data["准考证号"],
  369. "sliceCount": config.subjective_num,
  370. "sheetCount": sheet_num,
  371. "answers": object_answerdata,
  372. "batchCode": "",
  373. "absent": False,
  374. "manual": student_data["maual"]
  375. }
  376. logger.info(student_upload_data)
  377. self.inf.scanstudent(student_upload_data)
  378. else:
  379. student_upload_data = {
  380. "examNumber": student_data["准考证号"],
  381. "sliceCount": 0,
  382. "sheetCount": 0,
  383. "answers": "",
  384. "batchCode": "",
  385. "absent": True,
  386. "manual": False
  387. }
  388. logger.info(student_upload_data)
  389. logger.info("缺考不做上传")
  390. #self.inf.scanstudent(student_upload_data)
  391. with open(student_temp_path+os.sep+"upload.json","w",encoding="utf-8") as file:
  392. json_str = json.dumps(uploadList, indent=4, ensure_ascii=False)
  393. file.write(json_str)
  394. generator=ftgenerator()
  395. # generator.studentgenerator()
  396. # # generator.papergenerator()
  397. # generator.importData()
  398. # generator.uploadstudent()
  399. generator.imagegenerator()
  400. #
  401. #