WORKS

実績・制作事例

サイトにチャットボット設置

6. チャットボットを制御するjsファイルの作成

前章で説明したチャットボットをブラウザサイドで制御するjavascriptについて説明します。
まずチャットボットを出したいサイトのHTMLでjavascriptを参照します。

<script src="https://api.sample.jp/chat/chatbot.js?site_token=XXXXXXXXXXXXXXX"></script>

“https://api.sample.jp” はチャットボットAPIのサーバーに置き換えてください。
“site_token=XXXXXXXXXXXXXXX” という引数がくっついていますが、これはチャットボットを利用するサイトごとにユニークになります。この設定は後述しますが、このトークンとサイトドメインの組み合わせが設定内容と一致している場合にのみ、チャットボットを利用できるようにします。
また、大量にチャットボットを利用されるとOpenAIへの課金がかさんでしまうため、当システムではサイトごとに1日の利用回数の上限も設けていることも、ここでお伝えしておきます。この利用回数上限設定の仕方についても後述します。
 
では、その辺も踏まえて chatbot.js の中身です。

chatbot.js

(function() {
  // スクリプト自身の src からトークン取得
  const script = document.currentScript
    || Array.from(document.getElementsByTagName('script'))
            .reverse().find(s => s.src && s.src.includes('chatbot.js'));
  if (!script) {
    console.error('Chatbot: script element not found');
    return;
  }
  const url = new URL(script.src);
  const SITE_TOKEN = url.searchParams.get('site_token') || script.dataset.siteToken;
  if (!SITE_TOKEN) {
    console.error('Chatbot: missing site_token');
    return;
  }

  // CSS 読み込み
  const cssHref = 'https://api.sample.jp/chat/style.css';
  if (!document.querySelector(`link[href="${cssHref}"]`)) {
    const link = document.createElement('link');
    link.rel  = 'stylesheet';
    link.href = cssHref;
    document.head.appendChild(link);
  }


  // ── 初期化処理 ──
  document.addEventListener('DOMContentLoaded', () => {
    const chatbot = document.getElementById('chatbot');
    if (!chatbot) {
      // チャットボット用要素がなければ何もしない
      return;
    }
    const header  = document.getElementById('chatbot-header');
    const inputEl = document.getElementById('chatbot-input');

    header.addEventListener('click', e => {
      e.stopPropagation();
      chatbot.classList.toggle('collapsed');
      chatbot.classList.toggle('expanded');
    });

    inputEl.addEventListener('keydown', function (e) {
      if (e.key === 'Enter' && this.value.trim() !== '') {
        const userInput = this.value.trim();
        this.value = '';
        addMessage('user', userInput);
        fetchOpenAIResponse(userInput, SITE_TOKEN);
      }
    });

    document.addEventListener('click', e => {
      if (!chatbot.contains(e.target) && chatbot.classList.contains('expanded')) {
        chatbot.classList.remove('expanded');
        chatbot.classList.add('collapsed');
      }
    });
  });

  // メッセージ追加関数
  function addMessage(sender, message) {
    const container = document.getElementById('chatbot-messages');
    const el = document.createElement('div');
    if (sender === 'user') {
      el.className = 'message user';
      el.innerHTML = `
        <img src="https://api.sample.jp/chat/icons/user.svg" class="avatar" alt="You">
        <span class="text">${message}</span>
      `;
    } else {
      el.className = 'message bot';
      el.innerHTML = `
        <img src="https://api.sample.jp/chat/icons/support.svg" class="avatar" alt="Support">
        <span class="text">${message}</span>
      `;
    }
    container.appendChild(el);
    container.scrollTop = container.scrollHeight;
  }

  // ページテキスト取得
  function getPageContext() {
    return document.body.innerText;
  }

  // API 呼び出し
  async function fetchOpenAIResponse(userInput, token) {
    const apiUrl = 'https://api.sample.jp/api/chat';
    try {
      const res = await fetch(`${apiUrl}?site_token=${encodeURIComponent(token)}`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          'X-Site-Token': token
        },
        body: JSON.stringify({
          message: userInput,
          pageContext: getPageContext()
        })
      });
      if (!res.ok) {
        if (res.status === 429) {
          // レート制限(日次クォータや分間制限)に引っかかった場合
          addMessage('bot', '利用回数の上限に達しました。しばらく待ってから再度お試しください。');
        } else {
          // その他のステータスコード
          addMessage('bot', `サーバーエラーが発生しました(${res.status})。しばらくしてからお試しください。`);
        }
        return;
      }
      const data = await res.json();
      if (data.reply) {
        addMessage('bot', data.reply);
      } else {
        console.error('Unexpected response', data);
        addMessage('bot', '応答の形式が正しくありません。');
      }
    } catch (err) {
      console.error('Fetch failed:', err);
      addMessage('bot', '通信中にエラーが発生しました。');
    }
  }
})();

 
①ユーザーが入力したら、その内容をチャットに出す。
②同時に、チャットボットAPIに対して、冒頭のsite_tokenを引数にぶらさげながら、メッセージを送る。
③レスポンスが来たら、チャットにメッセージを出す。
※ チャットボット用のスタイルシートも読み込んでますので、ここで初めてチャットボットのレイアウトがきれいに現れてきます。

という大筋です。

チャットボットの窓の開閉やエラー処理の詳細については、だいたい読めば分かるかと思いますので、上記のコードの紹介までとし、詳細の説明は省略させてください。
 
次は設定ファイルについて説明します。