codeboosterstech commited on
Commit
0d3fcab
·
verified ·
1 Parent(s): d5b3078

Update docx_builder.py

Browse files
Files changed (1) hide show
  1. docx_builder.py +60 -176
docx_builder.py CHANGED
@@ -1,177 +1,61 @@
1
- """
2
- DOCX document generation using python-docx
3
- """
4
-
5
  from docx import Document
6
- from docx.shared import Inches
7
- from docx.enum.text import WD_ALIGN_PARAGRAPH
8
- from typing import Dict, Any, List
9
- import os
10
-
11
- class DocxBuilder:
12
- """Builds DOCX outputs for question papers, answers, and OBE reports"""
13
-
14
- def __init__(self):
15
- self.doc = None
16
-
17
- def build_question_paper(self, data: Dict[str, Any], subject: str, stream: str) -> Document:
18
- """Build question paper DOCX"""
19
- self.doc = Document()
20
-
21
- # Title section
22
- title = self.doc.add_heading(f'{subject} - Question Paper', 0)
23
- title.alignment = WD_ALIGN_PARAGRAPH.CENTER
24
-
25
- # Metadata
26
- self.doc.add_paragraph(f'Stream: {stream}')
27
- self.doc.add_paragraph(f'Total Marks: {self._calculate_total_marks(data)}')
28
- self.doc.add_paragraph('')
29
-
30
- # Instructions
31
- self._add_instructions(stream)
32
-
33
- # Questions by part
34
- self._add_part_questions(data, "A", "Part A - Answer ALL Questions")
35
- self._add_part_questions(data, "B", "Part B - Answer ALL Questions (Either/Or)")
36
- self._add_part_questions(data, "C", "Part C - Case Study (Answer ALL Questions)")
37
-
38
- return self.doc
39
-
40
- def build_answer_key(self, data: Dict[str, Any], subject: str) -> Document:
41
- """Build answer key DOCX"""
42
- self.doc = Document()
43
-
44
- title = self.doc.add_heading(f'{subject} - Model Answer Key', 0)
45
- title.alignment = WD_ALIGN_PARAGRAPH.CENTER
46
-
47
- if "answers" in data:
48
- for answer in data["answers"]:
49
- self.doc.add_heading(f'Question {answer["question_ref"]}', level=2)
50
- self.doc.add_paragraph(f'Model Answer: {answer.get("model_answer", "N/A")}')
51
-
52
- if "marking_scheme" in answer:
53
- self.doc.add_paragraph("Marking Scheme:")
54
- for point in answer["marking_scheme"]:
55
- self.doc.add_paragraph(point, style='List Bullet')
56
-
57
- self.doc.add_paragraph('')
58
-
59
- return self.doc
60
-
61
- def build_obe_summary(self, data: Dict[str, Any], subject: str) -> Document:
62
- """Build OBE summary report DOCX"""
63
- self.doc = Document()
64
-
65
- title = self.doc.add_heading(f'{subject} - OBE Summary Report', 0)
66
- title.alignment = WD_ALIGN_PARAGRAPH.CENTER
67
-
68
- if "obe" in data:
69
- obe_data = data["obe"]
70
-
71
- # Course Outcomes
72
- self.doc.add_heading('Course Outcome Mapping', level=2)
73
- if "course_outcomes" in obe_data:
74
- for co, info in obe_data["course_outcomes"].items():
75
- self.doc.add_paragraph(f'{co}: {info.get("coverage", "N/A")} coverage')
76
- if "questions" in info:
77
- self.doc.add_paragraph(f'Questions: {", ".join(info["questions"])}')
78
-
79
- # Bloom's Distribution
80
- self.doc.add_heading("Bloom's Taxonomy Distribution", level=2)
81
- if "bloom_distribution" in obe_data:
82
- for level, percentage in obe_data["bloom_distribution"].items():
83
- self.doc.add_paragraph(f'{level}: {percentage}')
84
-
85
- # Analysis
86
- self.doc.add_heading('Quality Analysis', level=2)
87
- self.doc.add_paragraph(f'Difficulty Index: {obe_data.get("difficulty_index", "N/A")}')
88
- self.doc.add_paragraph(f'Unit Coverage: {obe_data.get("unit_coverage", "N/A")}')
89
-
90
- if "recommendations" in obe_data:
91
- self.doc.add_paragraph(f'Recommendations: {obe_data["recommendations"]}')
92
-
93
- return self.doc
94
-
95
- def _calculate_total_marks(self, data: Dict[str, Any]) -> int:
96
- """Calculate total marks from questions"""
97
- total = 0
98
- if "final_qp" in data and "questions" in data["final_qp"]:
99
- for question in data["final_qp"]["questions"]:
100
- total += question.get("marks", 0)
101
- return total
102
-
103
- def _add_instructions(self, stream: str):
104
- """Add stream-specific instructions"""
105
- instructions = self.doc.add_paragraph('INSTRUCTIONS:')
106
- instructions.bold = True
107
-
108
- if stream == "CSE":
109
- self.doc.add_paragraph('• Part A: Answer ALL questions (2 marks each)')
110
- self.doc.add_paragraph('• Part B: Answer ALL questions (13 marks each) - Choose either (a) or (b)')
111
- self.doc.add_paragraph('• Part C: Case study (14 marks) - Answer ALL sub-questions')
112
- self.doc.add_paragraph('• Questions are tagged with relevant company standards (MAANGO BIG15)')
113
- else:
114
- self.doc.add_paragraph('• Part A: Answer ALL questions (2 marks each)')
115
- self.doc.add_paragraph('• Part B: Answer ALL questions (13 marks each) - Choose either (a) or (b)')
116
- self.doc.add_paragraph('• Part C: Case study (14 marks) - Answer ALL sub-questions')
117
- self.doc.add_paragraph('• Questions follow GATE examination patterns')
118
-
119
- self.doc.add_paragraph('')
120
-
121
- def _add_part_questions(self, data: Dict[str, Any], part: str, heading: str):
122
- """Add questions for specific part"""
123
- self.doc.add_heading(heading, level=1)
124
-
125
- if "final_qp" in data and "questions" in data["final_qp"]:
126
- part_questions = [q for q in data["final_qp"]["questions"] if q.get("part") == part]
127
-
128
- for question in part_questions:
129
- # Question header
130
- q_header = f'Q{question["question_no"]}'
131
- if question.get("sub_no"):
132
- q_header += f'({question["sub_no"]})'
133
- q_header += f' [{question["marks"]} marks]'
134
-
135
- self.doc.add_paragraph(q_header).bold = True
136
-
137
- # Question text
138
- self.doc.add_paragraph(question["question_text"])
139
-
140
- # Metadata
141
- meta = self.doc.add_paragraph()
142
- meta.add_run(f'Unit: {question["unit"]} | ')
143
- meta.add_run(f'Bloom: {question["bloom_level"]} | ')
144
- meta.add_run(f'CO: {question["course_outcome"]} | ')
145
- meta.add_run(f'Tags: {", ".join(question["tags"])}')
146
- meta.style.font.italic = True
147
-
148
- self.doc.add_paragraph('')
149
-
150
- def save_document(self, doc: Document, filename: str):
151
- """Save document to file"""
152
- doc.save(filename)
153
-
154
- def generate_all_documents(final_output: Dict[str, Any], subject: str, stream: str, output_dir: str = "."):
155
- """Generate all three DOCX files"""
156
- builder = DocxBuilder()
157
-
158
- # Question Paper
159
- qp_doc = builder.build_question_paper(final_output, subject, stream)
160
- qp_filename = f"{output_dir}/{subject}_QuestionPaper.docx"
161
- builder.save_document(qp_doc, qp_filename)
162
-
163
- # Answer Key
164
- ak_doc = builder.build_answer_key(final_output, subject)
165
- ak_filename = f"{output_dir}/{subject}_KeyAnswers.docx"
166
- builder.save_document(ak_doc, ak_filename)
167
-
168
- # OBE Summary
169
- obe_doc = builder.build_obe_summary(final_output, subject)
170
- obe_filename = f"{output_dir}/{subject}_OBE_Summary.docx"
171
- builder.save_document(obe_doc, obe_filename)
172
-
173
- return {
174
- "question_paper": qp_filename,
175
- "answer_key": ak_filename,
176
- "obe_summary": obe_filename
177
- }
 
 
 
 
 
1
  from docx import Document
2
+ from docx.shared import Pt
3
+ import json
4
+
5
+
6
+ def _add_text(doc, text, bold=False):
7
+ p = doc.add_paragraph()
8
+ run = p.add_run(text)
9
+ run.bold = bold
10
+ run.font.size = Pt(11)
11
+
12
+
13
+ def build_question_paper_docx(path, final_json, generator_raw, subject):
14
+ doc = Document()
15
+ doc.add_heading(f"Question Paper — {subject}", level=1)
16
+
17
+ _add_text(doc, "Printable Version:", True)
18
+ _add_text(doc, generator_raw[:8000])
19
+
20
+ # Structured table
21
+ questions = final_json.get("final_qp", {}).get("questions", [])
22
+ if questions:
23
+ table = doc.add_table(rows=1, cols=5)
24
+ hdr = table.rows[0].cells
25
+ hdr[0].text = "Q.No"
26
+ hdr[1].text = "SubQ"
27
+ hdr[2].text = "Question"
28
+ hdr[3].text = "CO"
29
+ hdr[4].text = "Bloom/Tags"
30
+
31
+ for q in questions:
32
+ row = table.add_row().cells
33
+ row[0].text = str(q.get("question_no", ""))
34
+ row[1].text = str(q.get("sub_no", ""))
35
+ row[2].text = q.get("question_text", "")
36
+ row[3].text = q.get("course_outcome", "")
37
+ row[4].text = q.get("bloom_level", "") + " | " + q.get("tags", "")
38
+
39
+ doc.save(path)
40
+
41
+
42
+ def build_answers_docx(path, final_json, subject):
43
+ doc = Document()
44
+ doc.add_heading(f"Answer Key {subject}", level=1)
45
+
46
+ answers = final_json.get("answers", {})
47
+ for k, v in answers.items():
48
+ _add_text(doc, f"{k}:", True)
49
+ _add_text(doc, str(v))
50
+
51
+ doc.save(path)
52
+
53
+
54
+ def build_obe_docx(path, final_json, subject):
55
+ doc = Document()
56
+ doc.add_heading(f"OBE Summary — {subject}", level=1)
57
+
58
+ obe = final_json.get("obe", {})
59
+ _add_text(doc, json.dumps(obe, indent=2))
60
+
61
+ doc.save(path)