Render html optional (#4478)
* allow user to render HTML in chat responses resolves #4476 * add file * Add translation for all non-en
This commit is contained in:
parent
8cdadd8cb3
commit
87c666466f
@ -804,6 +804,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -843,6 +843,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -546,6 +546,10 @@ const TRANSLATIONS = {
|
||||
icon: "Icon",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -564,6 +564,11 @@ const TRANSLATIONS = {
|
||||
icon: "Icon",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: "Render HTML in chat",
|
||||
description:
|
||||
"Render HTML responses in assistant responses.\nThis can result in a much higher fidelity of response quality, but can also lead to potential security risks.",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@ -557,6 +557,10 @@ const TRANSLATIONS = {
|
||||
icon: "Icono",
|
||||
link: "Enlace",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -523,6 +523,10 @@ const TRANSLATIONS = {
|
||||
icon: "Ikoon",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -796,6 +796,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -804,6 +804,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -529,6 +529,10 @@ const TRANSLATIONS = {
|
||||
icon: "סמל",
|
||||
link: "קישור",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -802,6 +802,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -835,6 +835,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -532,6 +532,10 @@ const TRANSLATIONS = {
|
||||
icon: "아이콘",
|
||||
link: "링크",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -541,6 +541,10 @@ const TRANSLATIONS = {
|
||||
icon: "Ikona",
|
||||
link: "Saite",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -799,6 +799,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -546,6 +546,10 @@ const TRANSLATIONS = {
|
||||
icon: "Ikona",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -531,6 +531,10 @@ const TRANSLATIONS = {
|
||||
icon: "Ícone",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -998,6 +998,10 @@ const TRANSLATIONS = {
|
||||
icon: "Iconiță",
|
||||
link: "Link",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -844,6 +844,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -799,6 +799,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -798,6 +798,10 @@ const TRANSLATIONS = {
|
||||
icon: null,
|
||||
link: null,
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -509,6 +509,10 @@ const TRANSLATIONS = {
|
||||
icon: "图标",
|
||||
link: "链接",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
api: {
|
||||
|
||||
@ -806,6 +806,10 @@ const TRANSLATIONS = {
|
||||
icon: "圖示",
|
||||
link: "連結",
|
||||
},
|
||||
"render-html": {
|
||||
title: null,
|
||||
description: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"main-page": {
|
||||
|
||||
@ -4,7 +4,8 @@ import { APPEARANCE_SETTINGS } from "@/utils/constants";
|
||||
* @typedef { 'showScrollbar' |
|
||||
* 'autoSubmitSttInput' |
|
||||
* 'autoPlayAssistantTtsResponse' |
|
||||
* 'enableSpellCheck'
|
||||
* 'enableSpellCheck' |
|
||||
* 'renderHTML'
|
||||
* } AvailableSettings - The supported settings for the appearance model.
|
||||
*/
|
||||
|
||||
@ -14,11 +15,12 @@ const Appearance = {
|
||||
autoSubmitSttInput: true,
|
||||
autoPlayAssistantTtsResponse: false,
|
||||
enableSpellCheck: true,
|
||||
renderHTML: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches any locally storage settings for the user
|
||||
* @returns {{showScrollbar: boolean}}
|
||||
* @returns {{showScrollbar: boolean, autoSubmitSttInput: boolean, autoPlayAssistantTtsResponse: boolean, enableSpellCheck: boolean, renderHTML: boolean}}
|
||||
*/
|
||||
getSettings: () => {
|
||||
try {
|
||||
|
||||
@ -5,6 +5,7 @@ import AutoSubmit from "../components/AutoSubmit";
|
||||
import AutoSpeak from "../components/AutoSpeak";
|
||||
import SpellCheck from "../components/SpellCheck";
|
||||
import ShowScrollbar from "../components/ShowScrollbar";
|
||||
import ChatRenderHTML from "../components/ChatRenderHTML";
|
||||
|
||||
export default function ChatSettings() {
|
||||
const { t } = useTranslation();
|
||||
@ -31,6 +32,7 @@ export default function ChatSettings() {
|
||||
<AutoSpeak />
|
||||
<SpellCheck />
|
||||
<ShowScrollbar />
|
||||
<ChatRenderHTML />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Appearance from "@/models/appearance";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function ChatRenderHTML() {
|
||||
const { t } = useTranslation();
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [renderHTML, setRenderHTML] = useState(false);
|
||||
|
||||
const handleChange = async (e) => {
|
||||
const newValue = e.target.checked;
|
||||
setRenderHTML(newValue);
|
||||
setSaving(true);
|
||||
try {
|
||||
Appearance.updateSettings({ renderHTML: newValue });
|
||||
} catch (error) {
|
||||
console.error("Failed to update appearance settings:", error);
|
||||
setRenderHTML(!newValue);
|
||||
}
|
||||
setSaving(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
function fetchSettings() {
|
||||
const settings = Appearance.getSettings();
|
||||
setRenderHTML(settings.renderHTML);
|
||||
}
|
||||
fetchSettings();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-0.5 my-4">
|
||||
<p className="text-sm leading-6 font-semibold text-white">
|
||||
{t("customization.items.render-html.title")}
|
||||
</p>
|
||||
<p className="text-xs text-white/60 w-1/2 whitespace-pre-line">
|
||||
{t("customization.items.render-html.description")}
|
||||
</p>
|
||||
<div className="flex items-center gap-x-4 pt-1">
|
||||
<label className="relative inline-flex cursor-pointer items-center">
|
||||
<input
|
||||
id="render_html"
|
||||
type="checkbox"
|
||||
name="render_html"
|
||||
value="yes"
|
||||
checked={renderHTML}
|
||||
onChange={handleChange}
|
||||
disabled={saving}
|
||||
className="peer sr-only"
|
||||
/>
|
||||
<div className="pointer-events-none peer h-6 w-11 rounded-full bg-[#CFCFD0] after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:shadow-xl after:border-none after:bg-white after:box-shadow-md after:transition-all after:content-[''] peer-checked:bg-[#32D583] peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-transparent"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
import { encode as HTMLEncode } from "he";
|
||||
import markdownIt from "markdown-it";
|
||||
import markdownItKatexPlugin from "./plugins/markdown-katex";
|
||||
import Appearance from "@/models/appearance";
|
||||
import hljs from "highlight.js";
|
||||
import "./themes/github-dark.css";
|
||||
import "./themes/github.css";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
const markdown = markdownIt({
|
||||
html: false,
|
||||
html: Appearance.get("renderHTML") ?? false,
|
||||
typographer: true,
|
||||
highlight: function (code, lang) {
|
||||
const uuid = v4();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user