@@ -925,6 +925,7 @@ def create_quiz(filename):
925925 num_questions = int (request .form .get ('num_questions' , 50 ))
926926 quiz_type = request .form .get ('quiz_type' , 'question_to_answer' )
927927 selection_method = request .form .get ('selection_method' , 'random' )
928+ include_answers = request .form .get ('include_answers' , 'no' )
928929
929930 # 範囲設定の取得
930931 range_start = request .form .get ('range_start' )
@@ -973,7 +974,7 @@ def create_quiz(filename):
973974 return redirect (url_for ('generate_quiz' , filename = filename ))
974975
975976 # PDF生成
976- pdf_buffer = create_test_pdf (selected_items , filename [:- 4 ], quiz_type )
977+ pdf_buffer = create_test_pdf (selected_items , filename [:- 4 ], quiz_type , include_answers )
977978
978979 # PDFをファイルとして返す
979980 return send_file (
@@ -983,14 +984,15 @@ def create_quiz(filename):
983984 mimetype = 'application/pdf'
984985 )
985986
986- def create_test_pdf (items , dataset_name , quiz_type ):
987+ def create_test_pdf (items , dataset_name , quiz_type , include_answers = 'no' ):
987988 """問題のPDFを作成(統一フォーマット:質問,回答)"""
988989 buffer = io .BytesIO ()
989990
990991 # フォント設定
991992 font_available = setup_fonts ()
992993
993- doc = SimpleDocTemplate (buffer , pagesize = A4 , topMargin = 20 * mm , bottomMargin = 20 * mm )
994+ doc = SimpleDocTemplate (buffer , pagesize = A4 , topMargin = 10 * mm , bottomMargin = 10 * mm ,
995+ leftMargin = 10 * mm , rightMargin = 10 * mm )
994996 story = []
995997
996998 # スタイル設定
@@ -1014,7 +1016,7 @@ def escape_japanese(text):
10141016 parent = styles ['Title' ],
10151017 fontName = 'Japanese' ,
10161018 fontSize = 16 ,
1017- spaceAfter = 20
1019+ spaceAfter = 5
10181020 )
10191021
10201022 question_style = ParagraphStyle (
@@ -1029,7 +1031,7 @@ def escape_japanese(text):
10291031 'CustomTitle' ,
10301032 parent = styles ['Title' ],
10311033 fontSize = 16 ,
1032- spaceAfter = 20
1034+ spaceAfter = 5
10331035 )
10341036
10351037 question_style = ParagraphStyle (
@@ -1048,7 +1050,7 @@ def escape_japanese(text):
10481050
10491051 title_paragraph = Paragraph (title_text , title_style )
10501052 story .append (title_paragraph )
1051- story .append (Spacer (1 , 10 * mm ))
1053+ story .append (Spacer (1 , 3 * mm ))
10521054
10531055 # 全ての問題を処理(50問を超えた場合は複数ページ)
10541056 total_items = len (items )
@@ -1076,7 +1078,7 @@ def escape_japanese(text):
10761078 page_title = escape_japanese (f"{ dataset_name } - 問題 (ページ { page_num } )" )
10771079
10781080 story .append (Paragraph (page_title , title_style ))
1079- story .append (Spacer (1 , 10 * mm ))
1081+ story .append (Spacer (1 , 3 * mm ))
10801082
10811083 # 表データを準備(2列構成:左側25問、右側25問)
10821084 table_data = []
@@ -1096,17 +1098,31 @@ def escape_japanese(text):
10961098 # 回答→質問
10971099 question_text = (left_item .get ('回答' ) or
10981100 left_item .get ('answer' ) or '' )
1101+ answer_text = (left_item .get ('質問' ) or
1102+ left_item .get ('question' ) or '' )
10991103 else :
11001104 # 質問→回答(デフォルト)
11011105 question_text = (left_item .get ('質問' ) or
11021106 left_item .get ('question' ) or '' )
1107+ answer_text = (left_item .get ('回答' ) or
1108+ left_item .get ('answer' ) or '' )
11031109
11041110 if question_text :
11051111 if font_available :
11061112 left_question = f"{ left_item .get ('番号' , current_item_index + i + 1 )} . { question_text } "
11071113 else :
11081114 left_question = escape_japanese (f"{ left_item .get ('番号' , current_item_index + i + 1 )} . { question_text } " )
1109- left_answer = "________________"
1115+
1116+ # 回答欄の処理
1117+ if include_answers == 'red' :
1118+ # 薄い赤字で回答を表示(赤シートで隠しやすいように)
1119+ if font_available :
1120+ left_answer = f"<font color='#FF6666'>{ answer_text } </font>"
1121+ else :
1122+ left_answer = f"<font color='#FF6666'>{ escape_japanese (answer_text )} </font>"
1123+ left_answer = Paragraph (left_answer , question_style )
1124+ else :
1125+ left_answer = "________________"
11101126 else :
11111127 left_question = ""
11121128 left_answer = ""
@@ -1121,17 +1137,31 @@ def escape_japanese(text):
11211137 # 回答→質問
11221138 question_text = (right_item .get ('回答' ) or
11231139 right_item .get ('answer' ) or '' )
1140+ answer_text = (right_item .get ('質問' ) or
1141+ right_item .get ('question' ) or '' )
11241142 else :
11251143 # 質問→回答(デフォルト)
11261144 question_text = (right_item .get ('質問' ) or
11271145 right_item .get ('question' ) or '' )
1146+ answer_text = (right_item .get ('回答' ) or
1147+ right_item .get ('answer' ) or '' )
11281148
11291149 if question_text :
11301150 if font_available :
11311151 right_question = f"{ right_item .get ('番号' , current_item_index + i + 26 )} . { question_text } "
11321152 else :
11331153 right_question = escape_japanese (f"{ right_item .get ('番号' , current_item_index + i + 26 )} . { question_text } " )
1134- right_answer = "________________"
1154+
1155+ # 回答欄の処理
1156+ if include_answers == 'red' :
1157+ # 薄い赤字で回答を表示(赤シートで隠しやすいように)
1158+ if font_available :
1159+ right_answer = f"<font color='#FF6666'>{ answer_text } </font>"
1160+ else :
1161+ right_answer = f"<font color='#FF6666'>{ escape_japanese (answer_text )} </font>"
1162+ right_answer = Paragraph (right_answer , question_style )
1163+ else :
1164+ right_answer = "________________"
11351165 else :
11361166 right_question = ""
11371167 right_answer = ""
@@ -1149,7 +1179,7 @@ def escape_japanese(text):
11491179 ])
11501180
11511181 # 表を作成(4列:問題、解答欄、問題、解答欄)
1152- table = Table (table_data , colWidths = [55 * mm , 35 * mm , 55 * mm , 35 * mm ], rowHeights = [8 * mm ] * len (table_data ))
1182+ table = Table (table_data , colWidths = [55 * mm , 35 * mm , 55 * mm , 35 * mm ], rowHeights = [6 * mm ] * len (table_data ))
11531183
11541184 # 表のスタイル設定
11551185 table .setStyle (TableStyle ([
@@ -1159,21 +1189,102 @@ def escape_japanese(text):
11591189 ('ALIGN' , (0 , 0 ), (- 1 , - 1 ), 'LEFT' ),
11601190 ('FONTNAME' , (0 , 0 ), (- 1 , 0 ), 'Japanese' if font_available else 'Helvetica-Bold' ),
11611191 ('FONTSIZE' , (0 , 0 ), (- 1 , 0 ), 10 ),
1162- ('BOTTOMPADDING' , (0 , 0 ), (- 1 , 0 ), 8 ),
1192+ ('BOTTOMPADDING' , (0 , 0 ), (- 1 , 0 ), 4 ),
11631193
11641194 # データ行のスタイル
11651195 ('FONTNAME' , (0 , 1 ), (- 1 , - 1 ), 'Japanese' if font_available else 'Helvetica' ),
11661196 ('FONTSIZE' , (0 , 1 ), (- 1 , - 1 ), 9 ),
11671197 ('GRID' , (0 , 0 ), (- 1 , - 1 ), 0.5 , colors .black ),
11681198 ('VALIGN' , (0 , 0 ), (- 1 , - 1 ), 'MIDDLE' ),
1169- ('LEFTPADDING' , (0 , 0 ), (- 1 , - 1 ), 3 ),
1170- ('RIGHTPADDING' , (0 , 0 ), (- 1 , - 1 ), 3 ),
1171- ('TOPPADDING' , (0 , 0 ), (- 1 , - 1 ), 6 ),
1172- ('BOTTOMPADDING' , (0 , 0 ), (- 1 , - 1 ), 6 ),
1199+ ('LEFTPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1200+ ('RIGHTPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1201+ ('TOPPADDING' , (0 , 0 ), (- 1 , - 1 ), 3 ),
1202+ ('BOTTOMPADDING' , (0 , 0 ), (- 1 , - 1 ), 3 ),
11731203 ]))
11741204
11751205 story .append (table )
11761206
1207+ # 回答を下部に含める場合は、回答セクションを追加
1208+ if include_answers == 'bottom' :
1209+ # 回答セクション用のスペース
1210+ story .append (Spacer (1 , 5 * mm ))
1211+
1212+ # 回答セクションのタイトル
1213+ if font_available :
1214+ answer_title_text = "回答"
1215+ else :
1216+ answer_title_text = escape_japanese ("回答" )
1217+
1218+ answer_title_style = ParagraphStyle (
1219+ 'AnswerTitle' ,
1220+ parent = styles ['Heading2' ],
1221+ fontName = 'Japanese' if font_available else 'Helvetica-Bold' ,
1222+ fontSize = 12 ,
1223+ spaceAfter = 3
1224+ )
1225+
1226+ story .append (Paragraph (answer_title_text , answer_title_style ))
1227+
1228+ # 回答データを作成(現在のページの問題に対応)
1229+ answer_data = []
1230+ answers_per_row = 5 # 1行に5個の回答を配置
1231+
1232+ for i , item in enumerate (page_items ):
1233+ # 回答テキストを取得
1234+ if quiz_type == 'answer_to_question' :
1235+ # 回答→質問の場合、質問が答え
1236+ answer_text = (item .get ('質問' ) or item .get ('question' ) or '' )
1237+ else :
1238+ # 質問→回答の場合、回答が答え
1239+ answer_text = (item .get ('回答' ) or item .get ('answer' ) or '' )
1240+
1241+ question_number = item .get ('番号' , current_item_index + i + 1 )
1242+
1243+ if font_available :
1244+ answer_entry = f"{ question_number } . { answer_text } "
1245+ else :
1246+ answer_entry = escape_japanese (f"{ question_number } . { answer_text } " )
1247+
1248+ answer_data .append (answer_entry )
1249+
1250+ # 回答を表形式で配置(1行に複数個)
1251+ answer_table_data = []
1252+ answer_style = ParagraphStyle (
1253+ 'AnswerStyle' ,
1254+ parent = styles ['Normal' ],
1255+ fontName = 'Japanese' if font_available else 'Helvetica' ,
1256+ fontSize = 8 ,
1257+ spaceAfter = 2
1258+ )
1259+
1260+ for i in range (0 , len (answer_data ), answers_per_row ):
1261+ row_data = []
1262+ for j in range (answers_per_row ):
1263+ if i + j < len (answer_data ):
1264+ # 薄い赤字で回答を表示
1265+ if font_available :
1266+ red_answer = f"<font color='#FF6666'>{ answer_data [i + j ]} </font>"
1267+ else :
1268+ red_answer = f"<font color='#FF6666'>{ answer_data [i + j ]} </font>"
1269+ row_data .append (Paragraph (red_answer , answer_style ))
1270+ else :
1271+ row_data .append ("" )
1272+ answer_table_data .append (row_data )
1273+
1274+ if answer_table_data :
1275+ answer_table = Table (answer_table_data , colWidths = [38 * mm ] * answers_per_row )
1276+ answer_table .setStyle (TableStyle ([
1277+ ('FONTNAME' , (0 , 0 ), (- 1 , - 1 ), 'Japanese' if font_available else 'Helvetica' ),
1278+ ('FONTSIZE' , (0 , 0 ), (- 1 , - 1 ), 8 ),
1279+ ('ALIGN' , (0 , 0 ), (- 1 , - 1 ), 'LEFT' ),
1280+ ('VALIGN' , (0 , 0 ), (- 1 , - 1 ), 'TOP' ),
1281+ ('LEFTPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1282+ ('RIGHTPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1283+ ('TOPPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1284+ ('BOTTOMPADDING' , (0 , 0 ), (- 1 , - 1 ), 2 ),
1285+ ]))
1286+ story .append (answer_table )
1287+
11771288 # 次のページの準備
11781289 current_item_index += current_page_items
11791290
@@ -1188,7 +1299,24 @@ def escape_japanese(text):
11881299 question_text = (item .get ('質問' ) or
11891300 item .get ('question' ) or '問題' )
11901301 story .append (Paragraph (f"{ i } . { question_text } Answer: ___________" , question_style ))
1191- story .append (Spacer (1 , 3 * mm ))
1302+ story .append (Spacer (1 , 1 * mm ))
1303+
1304+ # フォールバック時も回答を含める
1305+ if include_answers == 'bottom' :
1306+ story .append (Spacer (1 , 5 * mm ))
1307+ story .append (Paragraph ("回答" , title_style ))
1308+ for i , item in enumerate (items , 1 ):
1309+ if quiz_type == 'answer_to_question' :
1310+ answer_text = (item .get ('質問' ) or item .get ('question' ) or '' )
1311+ else :
1312+ answer_text = (item .get ('回答' ) or item .get ('answer' ) or '' )
1313+ # 薄い赤字で回答を表示
1314+ red_answer = f"<font color='#FF6666'>{ i } . { answer_text } </font>"
1315+ story .append (Paragraph (red_answer , question_style ))
1316+ elif include_answers == 'red' :
1317+ # 赤字で回答を表示する場合は既に問題文に含まれているのでここでは何もしない
1318+ pass
1319+
11921320 doc .build (story )
11931321
11941322 buffer .seek (0 )
0 commit comments