FessのRAGチャットでMarkdownレンダリングに対応

FessのRAGチャット機能で、LLMからの応答をMarkdownとしてレンダリングできるようにしました。これにより、見出しやテーブル、コードブロックなどが整形された状態で表示されるようになります。また、ストリーミング中の途中の応答も適切にMarkdownとして表示されます。

背景

これまでFessのチャット画面では、LLMからの応答をプレーンテキストとして表示していました。LLMの応答にはMarkdown形式で見出しやリスト、コードブロックなどが含まれることが多いため、そのまま表示すると読みにくい状態でした。特にストリーミング応答中は、Markdownのソースがそのまま見えてしまう問題がありました。

変更内容

marked.jsとDOMPurifyの導入

クライアントサイドでMarkdownをHTMLに変換するために、marked.js(v17.0.4)を導入しました。また、XSS対策としてDOMPurifyを組み合わせて使用しています。

サニタイズポリシーは、サーバーサイドのMarkdownRenderer(OWASPサニタイザー)と同等の設定にしています。

  • 許可するHTMLタグを限定(見出し、リスト、テーブル、コードブロックなど)
  • リンクにはrel="nofollow"を自動付与
  • class属性はcodeprespandiv要素のみに制限
  • data-*属性は不許可
  • URIはhttps?://のみ許可

ストリーミング対応

ストリーミング応答では、受信中のテキストに対してrenderMarkdown()を呼び出すことで、途中の応答もMarkdownとしてレンダリングされます。従来の.text()による表示を.html(renderMarkdown())に変更し、リアルタイムにMarkdown変換を行っています。

CSSスタイルの追加

レンダリングされたMarkdown要素に対して、チャットUIに適したスタイルを追加しました。

  • 見出し(h1〜h6)のフォントサイズとマージン
  • テーブルのボーダーとパディング
  • 引用ブロックの左ボーダー
  • リンクの色とホバースタイル

フォールバック

marked.jsやDOMPurifyの読み込みに失敗した場合は、従来どおりHTMLエスケープしたプレーンテキストとして表示するフォールバック処理を実装しています。

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です