SmartStageで、タイムラインでのやりとりをもとに生成AIによってFAQを自動生成する方法をご案内します。
目次
完成イメージ
例えば、「FAQを生成し登録判断をする」というアクションを実行すると、タイムラインでやり取りした内容をもとにFAQが生成されます。
生成AIがFAQを生成できるように、このアクション「FAQを生成し登録判断をする」に、以下の手順でJavaScriptを適用していきます。
事前準備
SmartStageのAPIトークンの発行
SmartStage APIを呼び出すには、認証用のAPIトークンの発行が必要です。
APIトークンの発行については、以下の記事を参照してください。
また、APIトークンは共通定数に設定することをおすすめします。
共通定数の設定については、以下の記事を参照してください。
生成AIのエンドポイントとAPIキー
生成AIを起動させるには、認証用のエンドポイントとAPIキーの発行が必要です。
生成AIのエンドポイントとAPIキーの発行については、弊社にお問い合わせください。(※お客様自身の生成AI環境をご利用の場合はお客様自身でご確認いただきますようお願いいたします。)
また、生成AIのAPIキーは共通定数に設定することをおすすめします。
共通定数の設定については、以下の記事を参照してください。
画面項目の追加
FAQデータベースに登録するデータを管理するため、以下の画面項目を追加します。
※画面項目名は運用に合わせて変更可能です。
生成AIを適用するデータストアに、生成AIの結果を管理するための画面項目を追加します。
設定箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「項目設定」>「項目リスト(+ボタン)」の順にクリックしてください。
項目名に画面項目の名称、項目の型に適切な画面項目型を設定し、「保存」をクリックしてください。
上記にならい、以下の項目を追加してください。
- 「FAQタイトル」(テキスト型)
- 「FAQ質問」(複数行テキスト型)
- 「FAQ回答」(複数行テキスト型)
- 「FAQ補足情報」(複数行テキスト型)
ワークスペースIDの取得
サンプルスクリプトのワークスペースIDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
- SmartStageの管理者ページであることを確認します。
- 右上にある歯車アイコン > ワークスペース設定の順にクリックします。
ここで確認できるワークスペースIDがお客様のワークスペースIDです。
データストアIDの取得
サンプルスクリプトのデータストアIDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「基本設定」の順にクリックしてください。
ここで確認できるデータストアIDがお客様のデータストアIDです。
アクションIDの取得
サンプルスクリプトのアクションIDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「データ操作設定」の順にクリックしてください。
ここで確認できる「内容を更新する」のアクションIDがお客様のアクションIDです。
画面項目IDの取得
サンプルスクリプトの登録対象画面項目IDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「項目設定」>「項目リスト」の対象画面項目名の順にクリックしてください。
ここで確認できる項目IDが登録対象画面項目IDです。
上記にならい、以下の項目を同様に確認してください。
- 「FAQタイトル」
- 「FAQ質問」
- 「FAQ回答」
- 「FAQ補足情報」
サンプルスクリプトの修正と配置
サンプルスクリプトの修正
サンプルスクリプトを、お好みのテキストエディタ(例:VSCode)にペーストしてください。
生成AIのエンドポイントの設定
サンプルスクリプトの「生成AIのエンドポイント」をお客様のものに更新します。
サンプルスクリプトの定数CHATGPT_API_ENDPOINT
の値に、ご利用中のAIのエンドポイントを設定してください。
※クレオ提供の生成AIをご利用中のお客様は、お問い合わせください。
※<>
は不要です。
ワークスペースIDの設定
サンプルスクリプトの「ワークスペースID」をお客様のものに更新します。
サンプルスクリプトの定数SS_WORKSPACE_ID
の値に、こちらで取得したIDを設定してください。
※<>
は不要です。
データストアIDの設定
サンプルスクリプトの「データストアID」をお客様のものに更新します。
サンプルスクリプトの定数SS_DATASTORE_ID_CHATGPT_P
の値に、こちらで取得したIDを設定してください。
※<>
は不要です。
アクションIDの設定
サンプルスクリプトの「アクションID」をお客様のものに更新します。
サンプルスクリプトの定数SS_CHATGPT_P_UPDATE
の値に、こちらで取得したIDを設定してください。
※<>
は不要です。
画面項目IDの設定
サンプルスクリプトの「画面項目ID」をお客様のものに更新します。
サンプルスクリプトの定数SS_FIELD_ID_XXXXXX
の値に、こちらで取得したIDを設定してください。
※<>
は不要です。
動作確認
サンプルスクリプトの配置
アクションスクリプト設定から「FAQを生成し登録判断をする」を選択し、ポストスクリプトに修正したサンプルスクリプトを配置します。
テスト実行
サンプルスクリプトを配置したら、「テスト実行」をクリックしてください。設定したポストスクリプトのJavaScriptが実行されます。
注意事項
- アクションスクリプトの実行によりFAQが生成されることを確認しやすくするため、事前にテストデータとなるタイムラインにデータを蓄積しておくことを推奨します。
- テストデータ(テスト実行するタスク)は、「アクション実行時に渡されるデータ」に表示されているタスクが対象となります。
サンプルスクリプト
タイムラインの内容を生成AIのプロンプトに投入し、FAQを生成するサンプルスクリプトです。
// --- 定数定義 --- // SmartStage API のエンドポイント const SMARTSTAGE_EXTERNAL_API_BASE_URL = "https://api.smart-stage.io"; // SmartStage外部公開APIベースURL const SMARTSTAGE_INTERNAL_API_BASE_URL = "https://app.smart-stage.io/apicore/v1"; // SmartStage内部APIベースURL // SmartStage 環境固有のID const SMARTSTAGE_WORKSPACE_ID "<ワークスペースID>"; //お客様のワークスペースID const SMARTSTAGE_CHATGPT_PROCESS_UPDATE_ACTION_ID = "<アクションID>"; //生成AIを利用したいデータストアのデータ操作「内容を更新する」のアクションID // SmartStage データストアID const SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID = "<データストアID>"; //生成AIを利用するデータストアのデータストアID // SmartStage 項目ID const SMARTSTAGE_FIELD_ID_TITLE = "<画面項目ID>"; //タイトルに利用している画面項目ID const SMARTSTAGE_FIELD_ID_CHATGPT_TITLE = "<画面項目ID>"; //ChatGPT 生成結果「タイトル」 const SMARTSTAGE_FIELD_ID_CHATGPT_QUESTION = "<画面項目ID>"; //ChatGPT 生成結果「質問」 const SMARTSTAGE_FIELD_ID_CHATGPT_ANSWER = "<画面項目ID>"; //ChatGPT 生成結果「回答」 const SMARTSTAGE_FIELD_ID_CHATGPT_EXPLANATION = "<画面項目ID>"; //ChatGPT 生成結果「追加説明情報」 const SMARTSTAGE_FIELD_ID_CHATGPT_PROCESS = "<画面項目ID>";//ChatGPT 生成結果「補足情報」 //FAQを生成する情報源 const SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT = "<画面項目ID>"; // 問い合わせ内容の項目ID const SMARTSTAGE_FIELD_ID_RESPONSE_CONTENT = "<画面項目ID>";// 回答内容の項目ID // ChatGPT APIのエンドポイント const CHATGPT_API_ENDPOINT = "<生成AIのエンドポイント>"; //クレオ提供の生成AIをご利用中のお客様はお問い合わせください。 const SMARTSTAGE_API_REQUEST_OPTIONS = { headers: { Authorization: `Bearer {SS_API_TOKEN}`,// APIトークンは環境変数に設定し取得します 'Content-Type': 'application/json', }, timeout: 50000, }; const CHATGPT_API_REQUEST_OPTIONS = { headers: { 'api-key': `{CHATGPT_API_KEY}`,// APIキーは環境変数に設定し取得します 'Content-Type': 'application/json', }, timeout: 50000, }; // `item` オブジェクトは環境変数として提供されるため、ここでは定義しません。 // 実行環境が `item` オブジェクトをグローバルスコープまたは適切な形で提供することを前提とします。 /** * ChatGPTに送信するリクエストの生成とFAQ生成 * @param {object} currentItemData - SmartStageの項目データ * @returns {Promise<string>} ChatGPTから生成されたFAQのJSON文字列 */ const systemPrompt = `ユーザからの質問に対する回答集のQAを作るために、step by stepで考えてください。 ステップ1:まず、応答履歴を要約して整理してください。 ステップ2:前のステップの結果を使用して、QA形式で質問内容、回答、必要に応じて追加説明の文章を作ってください。 ステップ3:作成した文章に矛盾点がある場合は、ステップ1戻ることも大切です。 ステップ4:作成した文章を、与えられた条件とJSON形式に沿って、JSON形式のみを出力してください。 #条件 ・与えられた情報以外は使わない。 ・マークダウンは使わない。 ・個人情報は含めない。 ・固有番号は含めない。 ・IPアドレスは一部を”xxx”に置き換える。 ・あいさつ文は含めない。 #JSON形式 { "faq": [ { "question": "質問内容", "answer": "回答内容", "explanation": "必要に応じた追加説明", "process":"質問からどのような課題があり、それをどのように理解して文章を作成したかの理由" } ] }`; const generateFaqFromChatGpt = async (currentItemData) => { // 質問と回答のデータを取得 const rawInquiryContent = String(currentItemData.fields[SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT]); // 問い合わせ内容 const formattedInquiryContent = rawInquiryContent.replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ const rawResponseContent = String(currentItemData.fields[SMARTSTAGE_FIELD_ID_RESPONSE_CONTENT]); // 回答内容 const formattedResponseContent = rawResponseContent.replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ // Timelineデータを取得 // item オブジェクトは環境変数として提供されることを前提とします。 const smartStageTimelineData = await fetchTimelineRecords(item.itemId, SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID); const formattedTimelineString = JSON.stringify(smartStageTimelineData).replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ const chatGptPromptContent = ` #質問: ${formattedInquiryContent} #回答: ${formattedResponseContent} #応答履歴: ${formattedTimelineString} `; const chatGptRequestPayload = { "messages": [{ role: "system", content: systemPrompt }, { role: "user", content: chatGptPromptContent }], "max_completion_tokens": 4000, "temperature": 1, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0, "model": "o4-mini" }; try { const chatGptApiResponse = await axios({ url: CHATGPT_API_ENDPOINT, method: 'post', data: chatGptRequestPayload, ...CHATGPT_API_REQUEST_OPTIONS, }).catch((e) => { logger.error(`ChatGPTでエラー:エラー情報: ${JSON.stringify(e)}`); throw false; }); logger.info(chatGptApiResponse); const generatedFaqMessage = chatGptApiResponse.data.choices[0].message.content; const finalFaqOutput = generatedFaqMessage; return finalFaqOutput; } catch (error) { logger.error("エラーが発生しました:", error); throw error; // エラーを再スローして呼び出し元で処理できるようにする } }; /** * SmartStageのタイムラインデータを取得する * @param {string} targetItemId - タイムラインを取得するアイテムのID * @param {string} datastoreId - アイテムが属するデータストアのID * @returns {Promise<object>} タイムラインデータ */ const fetchTimelineRecords = async (targetItemId, datastoreId) => { const timelineResponse = await axios(`${SMARTSTAGE_INTERNAL_API_BASE_URL}/items/${targetItemId}/timelines?datastoreid=${datastoreId}`, SMARTSTAGE_API_REQUEST_OPTIONS) .catch( (error) => { logger.error(`アイテムタイムライン取得に失敗しました。 エラー情報: ${JSON.stringify(error)}`); throw error; // エラーを再スロー } ); return timelineResponse.data; }; // 「外部連携設定」「共通定数」に「SS_API_TOKEN」という名前でAPIトークンを登録してください /** * SmartStageのアイテムデータを取得する * @param {string} targetItemId - 取得するアイテムのID * @param {string} datastoreId - アイテムが属するデータストアのID * @returns {Promise<object>} アイテムのデータオブジェクト */ const fetchSmartStageItemData = async (targetItemId, datastoreId) => { const itemDataResponse = await axios({ method: 'get', url: `${SMARTSTAGE_INTERNAL_API_BASE_URL}/items/${targetItemId}?datastoreid=${datastoreId}`, ...SMARTSTAGE_API_REQUEST_OPTIONS, }) .catch((error) => { logger.error(`SmartStageアイテムの取得に失敗しました。エラー情報: ${JSON.stringify(error)}`); throw error; }); return (itemDataResponse.data); }; /** * アイテムを取得する (外部API用) * @param {string} targetItemId アイテムID * @param {string} datastoreId データストアID * @returns {object} アイテム情報 */ const fetchExternalSmartStageItem = async (targetItemId, datastoreId) => { const externalItemResponse = await axios(`${SMARTSTAGE_EXTERNAL_API_BASE_URL}/items/${targetItemId}?datastoreid=${datastoreId}`, SMARTSTAGE_API_REQUEST_OPTIONS).catch( (error) => { logger.error(`外部SmartStageアイテム取得に失敗しました。 エラー情報: ${error}`); throw error; // エラーを再スロー } ); return externalItemResponse.data; }; /** * SmartStageのフィールドデータを取得する * @param {string} targetItemId - 取得するアイテムのID * @param {string} datastoreId - アイテムが属するデータストアのID * @returns {Promise<object>} フィールドデータ */ const fetchSmartStageFields = async (targetItemId, datastoreId) => { const fieldsResponse = await axios(`${SMARTSTAGE_EXTERNAL_API_BASE_URL}/items/${targetItemId}?datastoreid=${datastoreId}`, SMARTSTAGE_API_REQUEST_OPTIONS) .catch( (error) => { logger.error(`SmartStageフィールド取得に失敗しました。 エラー情報: ${JSON.stringify(error)}`); throw error; // エラーを再スロー } ); return fieldsResponse.data.fields; }; /** * ワークスペースIDを取得する * @param {string} workspaceName ワークスペース名 * @returns {string} ワークスペースID * @throws {Error} ワークスペース情報の取得に失敗した場合 */ const fetchSmartStageWorkspaceId = async (workspaceName) => { const workspacesApiResponse = await axios(`${SMARTSTAGE_INTERNAL_API_BASE_URL}/workspaces`, SMARTSTAGE_API_REQUEST_OPTIONS).catch((error) => { logger.error(`ワークスペース情報の取得に失敗しました1。エラー情報: ${error}`); throw error; }); if (!(workspacesApiResponse && workspacesApiResponse.data && workspacesApiResponse.data.length > 0)) { logger.error('ワークスペース情報の取得に失敗しました2。'); throw new Error('ワークスペース情報の取得に失敗しました。'); } const foundWorkspaceData = workspacesApiResponse.data.find((d) => { return d.name === workspaceName; }); if (!foundWorkspaceData) { logger.error('ワークスペース情報の取得に失敗しました'); throw new Error('ワークスペース情報の取得に失敗しました。'); } logger.info(`ワークスペースID取得成功: ${foundWorkspaceData.workspaceId}`); // 成功ログは残す return foundWorkspaceData.workspaceId; }; /** * レコードを更新する * @param {string} workspaceId ワークスペースID * @param {string} targetItemId アイテムID * @param {string} faqUpdateDataString - 更新するFAQデータを含むJSON文字列 * @returns {Promise<object>} 更新APIのレスポンス * @throws {Error} 更新処理に失敗した場合 */ const updateSmartStageTicket = async (workspaceId, targetItemId, faqUpdateDataString) => { let parsedFaqUpdateData; try { parsedFaqUpdateData = JSON.parse(faqUpdateDataString); } catch (error) { logger.error(`JSONパースエラー: ${error.message}`); throw new Error("更新データが不正なJSON形式です。"); } const faqEntry = parsedFaqUpdateData.faq && parsedFaqUpdateData.faq[0]; if (!faqEntry) { logger.error("FAQデータが期待される形式ではありません。"); throw new Error("更新データにFAQ情報が含まれていません。"); } const requestPayload = { comment: `ChatGPTにより更新しました。`, fields: { // item.title は環境変数として提供されることを前提とします。 [SMARTSTAGE_FIELD_ID_TITLE]: item.title, [SMARTSTAGE_FIELD_ID_CHATGPT_QUESTION]: faqEntry.question, [SMARTSTAGE_FIELD_ID_CHATGPT_ANSWER]: faqEntry.answer, [SMARTSTAGE_FIELD_ID_CHATGPT_EXPLANATION]: faqEntry.explanation, [SMARTSTAGE_FIELD_ID_CHATGPT_PROCESS]: faqEntry.process }, datastoreId: SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID, workspaceId: workspaceId, }; const updateApiResponse = await axios({ method: 'post', url: `${SMARTSTAGE_EXTERNAL_API_BASE_URL}/items/${targetItemId}/actions/${SMARTSTAGE_CHATGPT_PROCESS_UPDATE_ACTION_ID}/update?name=false`, data: requestPayload, ...SMARTSTAGE_API_REQUEST_OPTIONS, }).catch((error) => { logger.error(`更新が失敗しました。 エラー情報: ${JSON.stringify(error)}`); throw error; }); return updateApiResponse.data; }; /** * メイン処理 */ const main = async () => { try { // このプロセスの項目データを取得する // item オブジェクトは環境変数として提供されることを前提とします。 const currentItemData = await fetchSmartStageItemData(item.itemId, SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID); // このプロセスのワークスペースIDを取得する const currentWorkspaceId = SMARTSTAGE_WORKSPACE_ID; // 定数から取得 // ChatGPTでFAQを生成する logger.info("ChatGPTによるFAQ生成を開始します。"); // 開始ログ const generatedFaqResult = await generateFaqFromChatGpt(currentItemData); logger.info("ChatGPTによるFAQ生成が完了しました。"); // 完了ログ logger.info(generatedFaqResult); // 生成されたFAQでチケットを更新する logger.info("SmartStageチケットの更新を開始します。"); // 開始ログ const ticketUpdateResult = await updateSmartStageTicket(currentWorkspaceId, item.itemId, generatedFaqResult); logger.info("メイン処理完了: チケットが正常に更新されました。"); // 最終完了ログ } catch (error) { logger.error("メイン処理でエラーが発生しました:", error.message); // 必要に応じて、ここでエラー通知などの追加処理を行う } }; // メイン処理の実行 main();
FAQへ自動連携する場合は、以下の記事も参照してください。
何かお困りのことはございますか?まずはヘルプセンターを検索してみましょう!
その他ご不明な点があれば、サポートチームにお問い合わせください。
コメント
0件のコメント
サインインしてコメントを残してください。