integrate_data.py (5568B)
1 import glob 2 import json 3 import os 4 from typing import Any, Dict, List, Tuple 5 6 7 def integrate_and_format_data(data_pairs: List[Dict[str, str]], output_file_path: str): 8 """ 9 Typstファイルと構造化JSONファイルを統合し、学習用のJSON Lines形式に変換する。 10 11 Args: 12 data_pairs: TypstファイルパスとJSONファイルパスの辞書のリスト。 13 output_file_path: 出力するJSON Linesファイルパス。 14 """ 15 16 formatted_data = [] 17 processed_count = 0 18 19 for pair in data_pairs: 20 typst_path = pair["typst_file"] 21 json_path = pair["json_file"] 22 23 if not os.path.exists(typst_path) or not os.path.exists(json_path): 24 print( 25 f"警告: ファイルペアが見つかりません - Typst: {typst_path}, JSON: {json_path}" 26 ) 27 continue 28 29 try: 30 # 1. Typstファイルの内容を読み込む 31 with open(typst_path, "r", encoding="utf-8") as f: 32 typst_content = f.read() 33 34 # 2. 構造化されたJSONのフィードバックリストを読み込む 35 with open(json_path, "r", encoding="utf-8") as f: 36 feedback_items = json.load(f) 37 38 # 3. フィードバックリストをJSON文字列に変換 39 # 改行やスペースを除去し、整形された単一のJSON文字列にする 40 feedback_output = json.dumps( 41 feedback_items, ensure_ascii=False, separators=(",", ":") 42 ) 43 44 # 4. LLM学習用のInstruction/Outputペアを作成 45 learning_example = {"instruction": typst_content, "output": feedback_output} 46 47 formatted_data.append(learning_example) 48 processed_count += 1 49 print(f"統合完了 ({processed_count}件目): {typst_path} と {json_path}") 50 51 except Exception as e: 52 print(f"エラー処理: {typst_path} / {json_path} - {e}") 53 54 # 5. すべてのデータをJSON Lines形式でファイルに書き出す 55 with open(output_file_path, "w", encoding="utf-8") as outfile: 56 for entry in formatted_data: 57 json.dump(entry, outfile, ensure_ascii=False) 58 outfile.write("\n") 59 60 print("\n--- 処理完了 ---") 61 print( 62 f"合計 {len(formatted_data)} 件の学習データが {output_file_path} に出力されました。" 63 ) 64 65 66 def find_file_pairs( 67 reports_dir: str, structured_dir: str, typst_base: str, json_base: str 68 ) -> List[Dict[str, str]]: 69 """ 70 構造化JSONファイルと連番に基づいて、対応するTypstファイルを検索し、ペアのリストを返す。 71 """ 72 data_pairs = [] 73 # 例: structured-feedback/structured_data_*.json にマッチ 74 search_pattern = os.path.join(structured_dir, f"{json_base}_*.json") 75 json_files = glob.glob(search_pattern) 76 77 for json_file_path in json_files: 78 try: 79 # structured_data_NNN.json から NNN を抽出 80 base_filename = os.path.basename(json_file_path) 81 parts = base_filename.replace(f"{json_base}_", "").split(".") 82 if len(parts) < 2 or not parts[0].isdigit(): 83 continue 84 85 sequence_num_str = parts[0] 86 87 # 対応するTypstファイル名を構築 (例: reports/report001.typ) 88 typst_file_name = f"{typst_base}{sequence_num_str}.typ" 89 typst_file_path = os.path.join(reports_dir, typst_file_name) 90 91 if os.path.exists(typst_file_path): 92 data_pairs.append( 93 { 94 "typst_file": typst_file_path, 95 "json_file": json_file_path, 96 } 97 ) 98 else: 99 print( 100 f"警告: JSONファイル {base_filename} に対応するTypstファイル " 101 f"({typst_file_name}) が {reports_dir} に見つかりませんでした。スキップします。" 102 ) 103 except Exception as e: 104 print(f"ファイルペアリング中にエラーが発生しました ({json_file_path}): {e}") 105 106 return data_pairs 107 108 109 if __name__ == "__main__": 110 # === 設定箇所 (ディレクトリとファイル名のベース) === 111 112 # Typstファイルが格納されているディレクトリ 113 REPORTS_DIR = "reports" 114 # 構造化JSONファイルが格納されているディレクトリ 115 STRUCTURED_DIR = "structured-feedback" 116 # Typstファイルのベース名 (例: report001.typ の 'report') 117 TYPST_BASE_NAME = "report" 118 # 構造化JSONファイルのベース名 (例: structured_data_001.json の 'structured_data') 119 JSON_BASE_NAME = "structured_data" 120 121 OUTPUT_FILE_NAME = "typst_feedback_dataset.jsonl" 122 123 # === スクリプト実行 === 124 125 # 構造化JSONファイルに基づいて、対応するTypstファイルを自動的に検索・ペアリング 126 file_pairs = find_file_pairs( 127 reports_dir=REPORTS_DIR, 128 structured_dir=STRUCTURED_DIR, 129 typst_base=TYPST_BASE_NAME, 130 json_base=JSON_BASE_NAME, 131 ) 132 133 if not file_pairs: 134 print( 135 "エラー: 処理対象のファイルペアが見つかりませんでした。ディレクトリとファイル名を確認してください。" 136 ) 137 else: 138 integrate_and_format_data(file_pairs, OUTPUT_FILE_NAME)