前回で作成したOpenAIチャットのデモはいろいろと改善点が盛りだくさんです。その1つは、OpenAIからのレスはテキストなのですがMarkdownの形式で来ます。今回はこの表示をHTMLに変換します。

OpenAIからのレス

OpenAIからのレスは以下のようなテキストできます。

 2023年10月4日以降の日本の祝日は以下の通りです:

- 体育の日(スポーツの日):10月9日
- 文化の日:11月3日
- 勤労感謝の日:11月23日

12月から年末までの祭日はありません。

MarkdownのWikiを参照すると、
上で使用されているハイフン(‐)は、順序無しリストのアイテム、HTMLでは<ul>の<li>の使用ということになります。

しかし、これを無視すると以下のような表示(前回)となります。

無視しないでHTMLに変換して、

のように表示したいです。

ソースコード

今回の機能を追加したソースコードは、前回のOpenAIチャットをもとにして違うgitブランチ(chat-openai-markdown)としました。

レポジトリはこちらですが、すでにデモのソースコードをインストールしているなら、以下でスイッチできます。

$ git fetch
$ git checkout chat-openai-markdown

を実行してブランチをゲットできます。

前回のブランチのchat-openaiとの差分は以下です。

$ git diff chat-openai --name-status
M       package-lock.json
M       package.json
M       resources/js/components/ChatMessages.vue

MarkdownのテキストからHTMLの変換のために、今回はmarkdown-itのパッケージが必要です。それゆえに以下の実行が必要です。

$ npm install

最後に、前回と同様に以下のコマンドを実行すると、ブラウザでテストが可能です。

$ npm run build
$ php artisan serve

markdown-itをChatMessages.vueに取り込む

差分で見たように、今回コードの変更はChatmessages.vueのみです。サーバー側ではなくフロントエンドでHTML変換です。
以下のコードで変更の部分にコメントしました。非常に簡単です。

<script setup>
import MarkdownIt from 'markdown-it'; // MarkdownからHTMLへの変換のパッケージ
const markdown = new MarkdownIt(); // 初期化

defineProps({
  messages: Array,
  user: Object
});
</script>

<template>
  <ul style="list-style:none">
    <li v-for="message in messages"
      :key="message.id"
      :class="message.user.id === user.id ? 'text-end' : 'text-start'">
      <div class="header">
        <strong>
          <span v-if="message.user.id === user.id">私</span>
          <span v-else>{{ message.user.name }}さん</span>
        </strong>
      </div>
      <p v-if="message.user.id === user.id">{{ message.message }}</p>
      <p v-else v-html="markdown.render(message.message)"></p> // ここでHTMLに変換
    </li>
  </ul>
</template>
// 以下は変換後のスタイル設定
<style>
ul {
  list-style-type: square;
}

pre, code {
  background-color:pink;
  padding: 4px;
}
</style>

以下は、コードのMarkdownをHTML変換した例です。

By khino