SPIRALは、主にエンタープライズ向けのローコードプラットフォームになります。ローコードプラットフォームなので、プログラミング知識がなくともWebアプリケーションを開発できるのが魅力です。
今回は、SPIRALのデータベースにあるお問い合わせデータを元にして、FAQを生成してみます。
元データについて
例えば以下のような内容です。
- 問い合わせ内容
パスワードを忘れてログインできません。再設定方法を教えてください。 - 回答
ログイン画面の「パスワードをお忘れの方」から登録メールアドレスを入力してください。再設定用リンクをお送りします。
このような内容を元に、FAQの文章をOpenAIのAPIを使って生成します。
元データのテーブル構造について
問い合わせデータを受け取るテーブルは以下のような形式となっています。 body と response 以外は今回は利用していません。
| No. | フィールド名 | フィールドタイプ | 差替キーワード |
|---|---|---|---|
| 1 | 問い合わせ日時 | 日付(○年○月○日 ○時○分) | contacted_at |
| 2 | 問い合わせ内容 | テキストエリア(1024 bytes) | body |
| 3 | 回答内容 | テキストエリア(1024 bytes) | response |
| 4 | カテゴリ | テキストフィールド(64 bytes) | category |
| 5 | チャネル | テキストフィールド(64 bytes) | channel |
| 6 | 顧客ID | テキストフィールド(64 bytes) | customer_id |
| 7 | 満足度 | 数字・記号・アルファベット(6 bytes) | satisfaction |
FAQ格納用テーブルについて
続いて、FAQを格納するテーブルです。こちらは元データのIDと、生成される内容を保存するフィールドだけあります。このテーブルは FAQList とします。
両フィールドとも入力必須としておきます。ここがポイントです。
| No. | フィールド名 | フィールドタイプ | 差替キーワード |
|---|---|---|---|
| 1 | 内容 | テキストエリア | body |
| 2 | id | 数字・記号・アルファベット | contact_id |
フォームを作成する
FAQListを対象として、フォームを作成します。
入力フォームは2つカスタマイズします。
- contact_id の入力は、お問い合わせ内容から選択する形にする
- 内容は初期表示では不要
contact_id の入力は、お問い合わせ内容から選択する形にする
入力フォーム時の表示をカスタマイズします。
<title></title> <!-- この下に追加 -->
<?php // <!-- SMP_DYNAMIC_PAGE DISPLAY_ERRORS=ON NAME=FAQ --> ?>
<?php
$selectdb = $SPIRAL->getDataBase("Contact");
$selectdb->addSelectFields("id", "body");
$searchResult = $selectdb->doSelect();
?>
これで $searchResult にお問い合わせ内容のデータが入ってくるので、 contact_id の入力を変更します。
<dl class="cf">
<dt class="title">
問い合わせ
</dt><dd class="data num">
<select name="contact_id" class="$errorInputColor:contact_id$">
<option value="">選択してください</option>
<?php
$list = $searchResult["data"];
foreach ($list as $select) {
$id = $select["id"];
$body = $select["body"];
$check = ($id == $SPIRAL->getParam("contact_id")) ? "selected" : "";
echo "<option value='" . $SPIRAL->escapeHtml($id) . "'" . $check . ">" . $SPIRAL->escapeHtml($body) . "</option>\n";
}
?>
</select><br>
<span class="msg">$error:contact_id$</span>
</dd>
</dl>
さらに、body は自動生成される内容なので、初期表示から消しておきます。
<?php if ($SPIRAL->getParam("contact_id") != "") { ?>
<dl class="cf">
<dt class="title">
内容
</dt><dd class="data ">
<textarea class="$errorInputColor:body$" name="body" rows="15" wrap="soft" ><?php echo $SPIRAL->escapeHtml($faqMarkdown); ?></textarea><br>
<span class="msg">$error:body$</span>
</dd>
</dl>
<?php } ?>
こうすると、最初の送信時には body がないので入力エラーになります。
初回送信時の処理
body がないので入力エラーになり、再度入力画面が呼ばれます。この時に、OpenAIのAPIを呼び出してFAQを生成します。
// 初回表示かどうかの判定
if ($SPIRAL->getParam("contact_id") != "") {
// 対象お問い合わせデータを取得
$id = $SPIRAL->getParam("contact_id");
$selectdb = $SPIRAL->getDataBase("Contact");
$selectdb->addEqualCondition("id", $id);
$selectdb->addSelectFields("id", "body", "response");
$searchResult = $selectdb->doSelect();
$result = $searchResult['data'][0];
// OpenAIのAPIキー
$apiKey = 'sk-proj-...';
// お問い合わせのデータ
$body = $result['body'];
$response = $result['response'];
// LLM用プロンプト
$prompt = <<<PROMPT
以下の2つの情報をもとに、FAQとしてそのまま使えるMarkdown文言を生成してください。
- 問い合わせ時のタイトル: {$body}
- 問い合わせへの返答: {$response}
要件:
- Markdown形式
- 簡潔で実務向け
- 個人情報や特定の業務要件を排除し、誰にとっても役立つ形
- 分かりやすく、可読性の高い文章
PROMPT;
$data = [
'model' => 'gpt-4.1-mini',
'input' => $prompt,
];
// APIリクエスト
$ch = curl_init('https://api.openai.com/v1/responses');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_POSTFIELDS => json_encode($data),
]);
$result = curl_exec($ch);
curl_close($ch);
$json = json_decode($result, true);
// APIレスポンスを取得
$faqMarkdown = '';
if (isset($json['output']) && is_array($json['output'])) {
foreach ($json['output'] as $out) {
if (!isset($out['content']) || !is_array($out['content'])) continue;
foreach ($out['content'] as $c) {
if (($c['type'] ?? '') === 'output_text' && isset($c['text'])) {
$faqMarkdown .= $c['text'];
}
}
}
}
// ```markdown となっている部分を除去
$faqMarkdown = preg_replace('/```markdown\n(.*?)```/s', '$1', $faqMarkdown);
}
これで $faqMarkdown にFAQ本文が入りますので、表示を行います。
<?php if ($SPIRAL->getParam("contact_id") != "") { ?>
<dl class="cf">
<dt class="title">
内容
</dt><dd class="data ">
<textarea class="$errorInputColor:body$" name="body" rows="15" wrap="soft" ><?php echo $SPIRAL->escapeHtml($faqMarkdown); ?></textarea><br>
<span class="msg">$error:body$</span>
</dd>
</dl>
<?php } ?>
これでFAQが生成され、 contact_id と body にデータが入るので、確認画面に遷移してデータ登録できます。
まとめ
LLMを使うことで、業務システムが省力化されたり、便利になるでしょう。ぜひSPIRALと組み合わせて使ってみてください。
現在、SPIRALではエンジニアβという無料アカウントを配布しています。SPIRALに興味がある型はこちらから試してみてください。
![FireShot Capture 242 - 通常DB一覧 - [pi-pe.smp.ne.jp].png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F197026%2Fd8ffc1ba-b906-4808-88f4-e6c3005d572f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=7fd13a97d0dde5e28dc5dfb042c0040c)
![FireShot Capture 248 - 通常DB一覧 - [pi-pe.smp.ne.jp].png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F197026%2F1a6e71af-6559-4623-9173-5133a1dbaad3.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=49cffae8f541c567dd98d8e998fcc7b0)

![FireShot Capture 249 - - [www.pi-pe.co.jp].png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F197026%2F4acc5283-cbde-4135-890d-e555f75fbd2f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=218a1f0e753ba9b946503a44ccb8450f)