ChatGPTやCopilotなどの生成AIは、既存プログラムの解析・リファクタリング・ドキュメント作成に非常に役立ちます。しかし実際の業務コードは複数ファイルで構成されており、そのまま貼り付けるわけにはいきません。
生成AIへのファイル添付には上限(多くの場合20ファイル前後)があるため、ある程度の規模のプログラムになると「どうやって全体を読ませるか」が課題になります。
この記事では、複数のソースファイルを1つのテキストファイルに自動マージするPythonスクリプトを紹介します。
なぜマージするのか
生成AIに複数ファイルのコードを理解させる方法は主に3つあります。
| 方法 | 手間 | 精度 |
|---|---|---|
| 複数回のプロンプトに分割して入力 | 大きい | 文脈が途切れやすい |
| プログラム専用AI(有償)を使う | 小さい | 高い |
| 複数ファイルを1つにマージして添付 | 小さい | 十分実用的 |
マージして1ファイルにまとめてしまえば、無料の汎用AIに丸ごと読ませることができます。
マージ形式のポイント
生成AIがそれぞれのファイルを別々のソースコードとして認識するには、以下のようにファイル名をヘッダとして挿入します。
===== a.c =====
#include <stdio.h>
...
int main(int argc, void **argv)
{
...
}
===== b.c =====
#include <stdio.h>
...
int func_bbb(int arg1, int arg2)
{
...
}
===== c.c =====
#include <stdio.h>
...
int func_ccc(int arg1, int arg2)
{
...
}
このフォーマットで入力すると、生成AIは各セクションを独立したファイルとして解析してくれます。
プロンプトにファイル数を明示するとより確実です。例:「以下は3つのCファイルをマージしたものです。」
ディレクトリ構造も一緒に渡す
ソースコードが複数のディレクトリに分散している場合は、以下のコマンドでツリー構造をテキストファイルに書き出して、マージファイルと一緒に添付します。
tree /f > tree.txt
これにより、生成AIがファイル間の依存関係やディレクトリ構成を把握した上で解析してくれます。
マージスクリプト(Python)
指定したディレクトリ以下の *.c *.cpp *.h を再帰的に検索して、1つのテキストファイルにまとめます。
import os
INPUT_ENCODING = "utf-8" # UTF-8でエンコードされたファイル
# INPUT_ENCODING = "CP932" # WindowsのShift_JIS互換でエンコードされたファイル
# INPUT_ENCODING = "utf-16" # UTF-16でエンコードされたファイル
# INPUT_ENCODING = "euc-jp" # EUC-JPでエンコードされたファイル
def collect_c_and_h_files(input_path, output_filename):
file_count = 0
with open(output_filename, "w", encoding="utf-8") as out_file:
# 指定パス以下の *.cpp, *.c, *.h を再帰的に検索
for root, dirs, files in os.walk(input_path):
for file_name in files:
if file_name.endswith((".cpp", ".c", ".h")):
full_path = os.path.join(root, file_name)
# ファイル名をヘッダとして出力
out_file.write(f"===== {file_name} =====\n")
# ファイルの中身を INPUT_ENCODING で読み込んで出力
try:
with open(full_path, "r", encoding=INPUT_ENCODING) as src_file:
out_file.write(src_file.read())
except UnicodeDecodeError:
out_file.write(f"[WARN] {INPUT_ENCODING}で読み込めませんでした\n")
# ファイル間の区切り
out_file.write("\n\n")
file_count += 1
print(f"{file_count}個のファイルが処理されました。")
if __name__ == "__main__":
input_path = input("検索するディレクトリのパスを入力してください:").strip()
output_filename = input("出力ファイル名を入力してください:").strip()
collect_c_and_h_files(input_path, output_filename)
print("完了しました。")
実行例
検索するディレクトリのパスを入力してください: C:\_ito\SRC\DS2\DS2
出力ファイル名を入力してください: C:\_ito\ds2_src.txt
23個のファイルが処理されました。
完了しました。
C:\_ito\SRC\DS2\DS2 以下の23ファイルが ds2_src.txt 1つにまとめられます。あとはこのファイルを生成AIに添付するだけです。
カスタマイズのポイント
ファイル名だけでなくパスも出力したい場合
# 変更前
out_file.write(f"===== {file_name} =====\n")
# 変更後
out_file.write(f"===== {full_path} =====\n")
同名ファイルが別ディレクトリに存在するケースでは、パス付きにする方が生成AIの混乱を防げます。
C/C++以外の言語に対応させたい場合
# 変更前
if file_name.endswith((".cpp", ".c", ".h")):
# Pythonの場合
if file_name.endswith(".py"):
# C#の場合
if file_name.endswith(".cs"):
文字コードについて
出力ファイルはUTF-8固定にしています。生成AIはUTF-8を確実に認識するためです。
入力ファイルの文字コードは INPUT_ENCODING で切り替えられます。変換がうまくいかない場合、出力ファイルに以下のような行が含まれます。
[WARN] utf-8で読み込めませんでした
この場合は INPUT_ENCODING をコメントアウト切り替えで変更してください。
おわりに
たった数十行のスクリプトですが、「大きなコードベースをAIに読ませる」という壁を一気に下げてくれます。レガシーコードの解析や、引き継いだプログラムの把握など、実際の業務で地味に役立っています。
その他の記事は BB研究所 で公開しています。