ChatGPTにエクセルファイルをプロンプトに送り、感想などの返答をもらう:簡単なAPIでの実装コード
[HttpPost("FromExcel")]
public async Task<string?> GetResult(IFormFile postedFile)
{
StringBuilder sb = new();
using var stream = postedFile.OpenReadStream();
var reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
while (reader.Read())
{
for (int col = 0; col < reader.FieldCount; col++)
{
Debug.WriteLine(reader.GetValue(col));
sb.Append(reader.GetValue(col));
sb.Append(',');
}
sb.Append(System.Environment.NewLine);
}
return await GetChatGptResponse("以下のドキュメントについての感想をください" + sb.ToString());
}
private async Task<string?> GetChatGptResponse(string prompt)
{
var openAiService = new OpenAIService(new OpenAiOptions()
{
ApiKey = "yourApiKey"
});
Console.WriteLine(prompt);
var result = await openAiService.Completions.CreateCompletion(new CompletionCreateRequest()
{
Prompt = prompt,
Echo = false,
MaxTokens = 300 // about
}, Models.TextDavinciV3);
if (result.Successful)
{
return result.Choices.Select(x => x.Text).FirstOrDefault();
}
else
return null;
}
実践的には下記のようなものも必要
Excelファイルには様々なデータ形式が存在します。数値、文字列、日付、さらには数式など、異なる形式のデータが混在しているため、GetValueメソッドで取得した値を適切に扱う必要があります。現在のコードではデータ型の処理がシンプルに扱われていますが、フォーマットごとに適切に処理することが求められます。
改善案:
nullの場合や、特定のフォーマットが必要な場合は、そのデータ型を明示的にチェックし、適切に処理するロジックを追加する。object value = reader.GetValue(col);
if (value != null)
{
if (value is DateTime)
sb.Append(((DateTime)value).ToString("yyyy-MM-dd"));
else if (value is double)
sb.Append(((double)value).ToString("F2"));
else
sb.Append(value.ToString());
}
APIキーをコードに直接書き込むのはセキュリティ上のリスクがあります。環境変数や設定ファイルを使用して、APIキーを安全に管理することが推奨されます。特にプロダクション環境では、APIキーが漏洩すると悪用される可能性があるため、適切なセキュリティ対策が必要です。
推奨方法:
appsettings.json)に保存し、コードから直接参照しないようにする。var apiKey = Environment.GetEnvironmentVariable("OpenAiApiKey");
var openAiService = new OpenAIService(new OpenAiOptions()
{
ApiKey = apiKey
});
非同期処理を活用することで、特に大規模なExcelファイルを処理する際のパフォーマンスが向上します。しかし、データが多い場合にはメモリの消費が増加する可能性があるため、ストリーム処理やメモリ管理を適切に行うことが重要です。
改善案:
asyncやawaitを活用した非同期処理を正しく実装し、レスポンスの高速化を図る。IAsyncEnumerableを使用し、大量のデータを逐次処理する設計に変更することも検討。ファイルが正しくアップロードされたかどうかの検証が重要です。例えば、ファイルが空だったり、対応していない形式のファイルがアップロードされた場合に、適切なエラーメッセージを返す仕組みを追加することで、ユーザーの混乱を避けられます。
実装例:
if (postedFile == null || postedFile.Length == 0)
{
return BadRequest("ファイルがアップロードされていません。");
}
if (!postedFile.FileName.EndsWith(".xlsx"))
{
return BadRequest("サポートされていないファイル形式です。");
}
現在の実装では、エラーが発生した際にnullを返していますが、より詳細なエラー情報をログに記録し、ユーザーに分かりやすいエラーメッセージを返すことで、デバッグや問題解決が容易になります。
改善案:
try-catchブロックを使って、例外が発生した場合に適切なエラーメッセージを記録し、ユーザーに返す。try
{
// Excelファイルの読み込みと処理
}
catch (Exception ex)
{
// ログにエラーを記録
_logger.LogError(ex, "Excelファイルの処理中にエラーが発生しました。");
return StatusCode(500, "内部エラーが発生しました。");
}
Excelファイルには複数のシートが含まれる場合があります。現在の実装では1つのシートしか処理していませんが、複数シートが存在する場合は、それぞれのシートを処理する機能を追加するとより柔軟です。
実装例:
ExcelReaderのNextResult()メソッドを使って、次のシートに移動しながら全シートを処理する。do
{
while (reader.Read())
{
// 各行の処理
}
} while (reader.NextResult()); // 次のシートに移動
ChatGPTに送信するテキストの量が多くなると、トークン制限に引っかかる可能性があります。特に、Excelファイルの内容が大きい場合には、適切にテキストを分割して送信したり、トークン数を制御する必要があります。
改善案:
MaxTokensで適切に設定し、応答が切れないようにする。