feat:解析题目生成试卷
This commit is contained in:
parent
f9cfd0f83b
commit
54c17e2a7f
|
@ -0,0 +1,95 @@
|
||||||
|
import pandas as pd
|
||||||
|
from docx import Document
|
||||||
|
from openpyxl import load_workbook
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
QUES_CLASS = '安全领域'
|
||||||
|
|
||||||
|
OPTION_LIST=[
|
||||||
|
[r"A:\s*(\S+)", "D"],
|
||||||
|
[r"B:\s*(\S+)", "E"],
|
||||||
|
[r"C:\s*(\S+)", "F"],
|
||||||
|
[r"D:\s*(\S+)", "G"],
|
||||||
|
[r"E:\s*(\S+)", "H"],
|
||||||
|
[r"F:\s*(\S+)", "I"],
|
||||||
|
]
|
||||||
|
|
||||||
|
def fill_excel(matches, excel_path, local):
|
||||||
|
wb = load_workbook(excel_path)
|
||||||
|
ws = wb.active
|
||||||
|
if matches:
|
||||||
|
ws[local] = matches
|
||||||
|
wb.save(excel_path)
|
||||||
|
|
||||||
|
|
||||||
|
def match_text(text, pattern):
|
||||||
|
matches = re.search(pattern, text)
|
||||||
|
if matches:
|
||||||
|
results = matches.group(1)
|
||||||
|
return results
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# 解析word文档
|
||||||
|
def interpret_text(start:int, excel_path:str, doc_path:str):
|
||||||
|
wordfile = Document(doc_path)
|
||||||
|
correct_dict = {}
|
||||||
|
option_dict = {}
|
||||||
|
question_type = {}
|
||||||
|
ques_text = {}
|
||||||
|
for index, p in enumerate(wordfile.paragraphs):
|
||||||
|
correct_answer = match_text(p.text, r"正确答案:\s*(\S+)") # 匹配正确答案
|
||||||
|
if correct_answer:
|
||||||
|
correct_dict.setdefault("correct_answer", []).append(correct_answer)
|
||||||
|
for e in OPTION_LIST: # 匹配选项
|
||||||
|
result = match_text(p.text, e[0])
|
||||||
|
if result:
|
||||||
|
option_dict.setdefault(e[1], []).append(result)
|
||||||
|
# 题目类型
|
||||||
|
# fill_excel(QUES_CLASS, excel_path, 'B'+str(index+start))
|
||||||
|
if p.text[:1]=='【' and p.text[4:5]=='】':
|
||||||
|
q_type = p.text[1:4] # 题目类型
|
||||||
|
question_type.setdefault("question_type", []).append(q_type)
|
||||||
|
if p.text[-2]=='分': #(3分)
|
||||||
|
question_text = p.text[5:-4].strip()
|
||||||
|
result = bool(re.match(r'\d+、', question_text)) # 处理题目前的序号
|
||||||
|
if result:
|
||||||
|
question = re.sub(r'\d+、', '',question_text)
|
||||||
|
ques_text.setdefault("question_text", []).append(question)
|
||||||
|
dict_list = [correct_dict,ques_text,option_dict,question_type]
|
||||||
|
for d in dict_list:
|
||||||
|
for key,value in d.items():
|
||||||
|
if key == "correct_answer":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'J'+str(start+v))
|
||||||
|
elif key == "question_type":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'A'+str(start+v))
|
||||||
|
fill_excel(QUES_CLASS, excel_path, 'B'+str(start+v))
|
||||||
|
elif key == "question_text":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'C'+str(start+v))
|
||||||
|
elif key == "D":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'D'+str(start+v))
|
||||||
|
elif key == "E":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'E'+str(start+v))
|
||||||
|
elif key == "F":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'F'+str(start+v))
|
||||||
|
elif key == "G":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'G'+str(start+v))
|
||||||
|
elif key == "H":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'H'+str(start+v))
|
||||||
|
elif key == "I":
|
||||||
|
for v in range(len(value)):
|
||||||
|
fill_excel(value[v], excel_path, 'I'+str(start+v))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
doc_path = "C:\code\data\\test.docx"
|
||||||
|
excel_path = "C:\code\data\question.xlsx"
|
||||||
|
interpret_text(3, excel_path, doc_path)
|
|
@ -63,6 +63,22 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
filterset_fields = ['level', 'type', 'year']
|
filterset_fields = ['level', 'type', 'year']
|
||||||
search_fields = ['name', 'options', 'resolution']
|
search_fields = ['name', 'options', 'resolution']
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post': 'question'}, serializer_class=Serializer)
|
||||||
|
def generate_paper(self, request):
|
||||||
|
"""
|
||||||
|
生成试卷
|
||||||
|
|
||||||
|
生成试卷
|
||||||
|
"""
|
||||||
|
print(request.data)
|
||||||
|
data = request.data.get('ids')
|
||||||
|
if data:
|
||||||
|
questions = Question.objects.filter(pk__in=data)
|
||||||
|
Serializer = QuestionSerializer(questions, many=True)
|
||||||
|
Serializer.data
|
||||||
|
return Response(Serializer.data, status=200)
|
||||||
|
|
||||||
|
|
||||||
@action(methods=['get'], detail=False,
|
@action(methods=['get'], detail=False,
|
||||||
url_path='export', url_name='export_question', perms_map=[{'get': '*'}], serializer_class=Serializer)
|
url_path='export', url_name='export_question', perms_map=[{'get': '*'}], serializer_class=Serializer)
|
||||||
def export_question(self, request):
|
def export_question(self, request):
|
||||||
|
@ -102,6 +118,7 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
qlist = ['A', 'B', 'C', 'D', 'E', 'F']
|
qlist = ['A', 'B', 'C', 'D', 'E', 'F']
|
||||||
leveldict = {'低': '低', '中': '中', '高': '高'}
|
leveldict = {'低': '低', '中': '中', '高': '高'}
|
||||||
notinlist = []
|
notinlist = []
|
||||||
|
ids = []
|
||||||
# 验证文件内容
|
# 验证文件内容
|
||||||
if sheet['a2'].value != '题目类型':
|
if sheet['a2'].value != '题目类型':
|
||||||
return Response({"error": "类型列错误!"})
|
return Response({"error": "类型列错误!"})
|
||||||
|
@ -171,6 +188,7 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
else:
|
else:
|
||||||
obj.level = '低'
|
obj.level = '低'
|
||||||
obj.save()
|
obj.save()
|
||||||
|
ids.append(obj.id)
|
||||||
elif type == '多选':
|
elif type == '多选':
|
||||||
right = list(right.strip())
|
right = list(right.strip())
|
||||||
if Question.objects.filter(type='多选', name=name, year=year, options=answer, questioncat=cateobj).exists():
|
if Question.objects.filter(type='多选', name=name, year=year, options=answer, questioncat=cateobj).exists():
|
||||||
|
@ -192,12 +210,13 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
else:
|
else:
|
||||||
obj.level = '低'
|
obj.level = '低'
|
||||||
obj.save()
|
obj.save()
|
||||||
|
ids.append(obj.id)
|
||||||
elif type == '判断':
|
elif type == '判断':
|
||||||
if right == 'A' or right == '对' or right == '正确':
|
if right == 'A' or right == '对' or right == '正确':
|
||||||
right = 'A'
|
right = 'A'
|
||||||
else:
|
else:
|
||||||
right = 'B'
|
right = 'B'
|
||||||
if Question.objects.filter(type='判断', name=name, is_delete=0, options={'A': '对', 'B': '错'}, questioncat=cateobj).exists():
|
if Question.objects.filter(type='判断', name=name, is_deleted=0, options={'A': '对', 'B': '错'}, questioncat=cateobj).exists():
|
||||||
notinlist.append(i)
|
notinlist.append(i)
|
||||||
else:
|
else:
|
||||||
obj = Question()
|
obj = Question()
|
||||||
|
@ -213,8 +232,9 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
else:
|
else:
|
||||||
obj.level = '低'
|
obj.level = '低'
|
||||||
obj.save()
|
obj.save()
|
||||||
|
ids.append(obj.id)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
return Response(notinlist, status=200)
|
return Response(notinlist, ids, status=200)
|
||||||
|
|
||||||
|
|
||||||
class PaperViewSet(ModelViewSet):
|
class PaperViewSet(ModelViewSet):
|
||||||
|
@ -358,7 +378,7 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
# return qs
|
# return qs
|
||||||
# else:
|
# else:
|
||||||
# return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
# return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
||||||
if has_permission('ability_review_jygl', self.request.user):
|
if has_permission('ctc_manager', self.request.user):
|
||||||
return qs
|
return qs
|
||||||
return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
||||||
|
|
||||||
|
@ -407,6 +427,7 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
if er.create_by != request.user:
|
if er.create_by != request.user:
|
||||||
raise ParseError('提交人有误')
|
raise ParseError('提交人有误')
|
||||||
exam = er.exam
|
exam = er.exam
|
||||||
|
paper = er.paper
|
||||||
if not exam:
|
if not exam:
|
||||||
raise ParseError('暂不支持')
|
raise ParseError('暂不支持')
|
||||||
if now > exam.close_time + timedelta(minutes=30):
|
if now > exam.close_time + timedelta(minutes=30):
|
||||||
|
@ -434,7 +455,8 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ParseError('判卷失败, 请检查试卷:' + str(e))
|
raise ParseError('判卷失败, 请检查试卷:' + str(e))
|
||||||
er.score = total_score
|
er.score = total_score
|
||||||
if er.score > 0.6*er.total_score:
|
# if er.score > 0.6*er.total_score:
|
||||||
|
if er.score >= paper.pass_score:
|
||||||
er.is_pass = True
|
er.is_pass = True
|
||||||
# 如果是自动发证
|
# 如果是自动发证
|
||||||
if exam.certificate:
|
if exam.certificate:
|
||||||
|
|
|
@ -62,9 +62,7 @@ class ImpMixin:
|
||||||
def gen_imp_view(self, request, start: int, mySerializer):
|
def gen_imp_view(self, request, start: int, mySerializer):
|
||||||
if 'file' not in request.data:
|
if 'file' not in request.data:
|
||||||
raise ParseError('请提供文件')
|
raise ParseError('请提供文件')
|
||||||
path = request.data['file']
|
path = request.data['file']
|
||||||
print(path, "---------ssss")
|
|
||||||
|
|
||||||
if not str(path).endswith('.xlsx'):
|
if not str(path).endswith('.xlsx'):
|
||||||
raise ParseError('请提供xlsx格式文件')
|
raise ParseError('请提供xlsx格式文件')
|
||||||
fullpath = settings.BASE_DIR + str(path)
|
fullpath = settings.BASE_DIR + str(path)
|
||||||
|
|
Loading…
Reference in New Issue