console.error(e));
};
+ /**
+ * Send a command to the LLM prompt input.
+ * @param {string} command - The command to send to the LLM
+ * @param {boolean} submit - Whether the command was submitted (default: false)
+ * @param {Object[]} history - The history of the chat
+ * @param {Object[]} attachments - The attachments to send to the LLM
+ * @returns {boolean} - Whether the command was sent successfully
+ */
const sendCommand = async (
command,
submit = false,
diff --git a/frontend/src/components/WorkspaceChat/index.jsx b/frontend/src/components/WorkspaceChat/index.jsx
index 90fafe5d03..0621693ec7 100644
--- a/frontend/src/components/WorkspaceChat/index.jsx
+++ b/frontend/src/components/WorkspaceChat/index.jsx
@@ -6,8 +6,13 @@ import paths from "@/utils/paths";
import ModalWrapper from "../ModalWrapper";
import { useParams } from "react-router-dom";
import { DnDFileUploaderProvider } from "./ChatContainer/DnDWrapper";
+import {
+ TTSProvider,
+ useWatchForAutoPlayAssistantTTSResponse,
+} from "../contexts/TTSProvider";
export default function WorkspaceChat({ loading, workspace }) {
+ useWatchForAutoPlayAssistantTTSResponse();
const { threadSlug = null } = useParams();
const [history, setHistory] = useState([]);
const [loadingHistory, setLoadingHistory] = useState(true);
@@ -64,9 +69,11 @@ export default function WorkspaceChat({ loading, workspace }) {
setEventDelegatorForCodeSnippets();
return (
-
-
-
+
+
+
+
+
);
}
diff --git a/frontend/src/components/contexts/TTSProvider.jsx b/frontend/src/components/contexts/TTSProvider.jsx
new file mode 100644
index 0000000000..a0c24e8092
--- /dev/null
+++ b/frontend/src/components/contexts/TTSProvider.jsx
@@ -0,0 +1,136 @@
+import { createContext, useContext, useEffect, useState } from "react";
+import System from "@/models/system";
+import Appearance from "@/models/appearance";
+
+const ASSISTANT_MESSAGE_COMPLETE_EVENT = "ASSISTANT_MESSAGE_COMPLETE_EVENT";
+const TTSProviderContext = createContext();
+
+/**
+ * This component is used to provide the TTS provider context to the application.
+ *
+ * TODO: This context provider simply wraps around the System.keys() call to get the TTS provider settings.
+ * However, we use .keys() in a ton of places and it might make more sense to make a generalized hook that
+ * can be used anywhere we need to get _any_ setting from the System by just grabbing keys() and reusing it
+ * as a hook where needed.
+ *
+ * For now, since TTSButtons are rendered on every message, we can save a ton of requests by just using this
+ * hook where for now so we can recycle the TTS settings in the chat container.
+ */
+export function TTSProvider({ children }) {
+ const [settings, setSettings] = useState({});
+ const [provider, setProvider] = useState("native");
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ async function getSettings() {
+ const _settings = await System.keys();
+ setProvider(_settings?.TextToSpeechProvider ?? "native");
+ setSettings(_settings);
+ setLoading(false);
+ }
+ getSettings();
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
+
+/**
+ * This hook is used to get the TTS provider settings easily without
+ * having to refetch the settings from the System.keys() call each component mount.
+ *
+ * @returns {{settings: {TTSPiperTTSVoiceModel: string|null}, provider: string, loading: boolean}} The TTS provider settings.
+ */
+export function useTTSProvider() {
+ const context = useContext(TTSProviderContext);
+ if (!context)
+ throw new Error("useTTSProvider must be used within a TTSProvider");
+ return context;
+}
+
+/**
+ * This function will emit the ASSISTANT_MESSAGE_COMPLETE_EVENT event.
+ *
+ * This event is used to notify the TTSProvider that a message has been fully generated and that the TTS response
+ * should be played if the user setting is enabled.
+ *
+ * @param {string} chatId - The chatId of the message that has been fully generated.
+ */
+export function emitAssistantMessageCompleteEvent(chatId) {
+ window.dispatchEvent(
+ new CustomEvent(ASSISTANT_MESSAGE_COMPLETE_EVENT, { detail: { chatId } })
+ );
+}
+
+/**
+ * This hook will establish a listener for the ASSISTANT_MESSAGE_COMPLETE_EVENT event.
+ * When the event is triggered, the hook will attempt to play the TTS response for the given chatId.
+ * It will attempt to play the TTS response for the given chatId until it is successful or the maximum number of attempts
+ * is reached.
+ *
+ * This is accomplished by looking for a button with the data-auto-play-chat-id attribute that matches the chatId.
+ */
+export function useWatchForAutoPlayAssistantTTSResponse() {
+ const autoPlayAssistantTtsResponse = Appearance.get(
+ "autoPlayAssistantTtsResponse"
+ );
+
+ function handleAutoPlayTTSEvent(event) {
+ let autoPlayAttempts = 0;
+ const { chatId } = event.detail;
+
+ /**
+ * Attempt to play the TTS response for the given chatId.
+ * This is a recursive function that will attempt to play the TTS response
+ * for the given chatId until it is successful or the maximum number of attempts
+ * is reached.
+ * @returns {boolean} true if the TTS response was played, false otherwise.
+ */
+ function attemptToPlay() {
+ const playBtn = document.querySelector(
+ `[data-auto-play-chat-id="${chatId}"]`
+ );
+ if (!playBtn) {
+ autoPlayAttempts++;
+ if (autoPlayAttempts > 3) return false;
+ setTimeout(() => {
+ attemptToPlay();
+ }, 1000 * autoPlayAttempts);
+ return false;
+ }
+ playBtn.click();
+ return true;
+ }
+ setTimeout(() => {
+ attemptToPlay();
+ }, 800);
+ }
+
+ // Only bother to listen for these events if the user has autoPlayAssistantTtsResponse
+ // setting enabled.
+ useEffect(() => {
+ if (autoPlayAssistantTtsResponse) {
+ window.addEventListener(
+ ASSISTANT_MESSAGE_COMPLETE_EVENT,
+ handleAutoPlayTTSEvent
+ );
+ return () => {
+ window.removeEventListener(
+ ASSISTANT_MESSAGE_COMPLETE_EVENT,
+ handleAutoPlayTTSEvent
+ );
+ };
+ } else {
+ console.log("Assistant TTS auto-play is disabled");
+ }
+ }, [autoPlayAssistantTtsResponse]);
+}
diff --git a/frontend/src/locales/ar/common.js b/frontend/src/locales/ar/common.js
index 6ec72d70eb..26af097443 100644
--- a/frontend/src/locales/ar/common.js
+++ b/frontend/src/locales/ar/common.js
@@ -99,6 +99,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -668,6 +669,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/da/common.js b/frontend/src/locales/da/common.js
index 3ea6de01b4..e6b421b109 100644
--- a/frontend/src/locales/da/common.js
+++ b/frontend/src/locales/da/common.js
@@ -101,6 +101,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -707,6 +708,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/de/common.js b/frontend/src/locales/de/common.js
index dd6d5f3f7a..a7cae3d367 100644
--- a/frontend/src/locales/de/common.js
+++ b/frontend/src/locales/de/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -705,6 +706,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/en/common.js b/frontend/src/locales/en/common.js
index 3ab9e20c91..ba1fea0d3a 100644
--- a/frontend/src/locales/en/common.js
+++ b/frontend/src/locales/en/common.js
@@ -83,6 +83,7 @@ const TRANSLATIONS = {
customization: "Customization",
interface: "UI Preferences",
branding: "Branding & Whitelabeling",
+ chat: "Chat",
"api-keys": "Developer API",
llm: "LLM",
transcription: "Transcription",
@@ -459,6 +460,19 @@ const TRANSLATIONS = {
description:
"White-label your AnythingLLM instance with custom branding.",
},
+ chat: {
+ title: "Chat",
+ description: "Set your chat preferences for AnythingLLM.",
+ auto_submit: {
+ title: "Auto-Submit Speech Input",
+ description:
+ "Automatically submit speech input after a period of silence",
+ },
+ auto_speak: {
+ title: "Auto-Speak Responses",
+ description: "Automatically speak responses from the AI",
+ },
+ },
items: {
theme: {
title: "Theme",
diff --git a/frontend/src/locales/es/common.js b/frontend/src/locales/es/common.js
index 82fe86933d..14a03c3fc1 100644
--- a/frontend/src/locales/es/common.js
+++ b/frontend/src/locales/es/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -667,6 +668,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/fa/common.js b/frontend/src/locales/fa/common.js
index b80235971e..d1c9a70775 100644
--- a/frontend/src/locales/fa/common.js
+++ b/frontend/src/locales/fa/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -660,6 +661,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/fr/common.js b/frontend/src/locales/fr/common.js
index 527ce41ffc..4023b0001c 100644
--- a/frontend/src/locales/fr/common.js
+++ b/frontend/src/locales/fr/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -668,6 +669,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/he/common.js b/frontend/src/locales/he/common.js
index e468b18a3a..2d741444a5 100644
--- a/frontend/src/locales/he/common.js
+++ b/frontend/src/locales/he/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -653,6 +654,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/it/common.js b/frontend/src/locales/it/common.js
index 7839bdd587..94c4d2ad54 100644
--- a/frontend/src/locales/it/common.js
+++ b/frontend/src/locales/it/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -666,6 +667,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/ja/common.js b/frontend/src/locales/ja/common.js
index 9aab675f44..09a3bf6ff4 100644
--- a/frontend/src/locales/ja/common.js
+++ b/frontend/src/locales/ja/common.js
@@ -100,6 +100,7 @@ const TRANSLATIONS = {
"browser-extension": "ブラウザ拡張",
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -699,6 +700,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/ko/common.js b/frontend/src/locales/ko/common.js
index 11c4383d46..947bc196c0 100644
--- a/frontend/src/locales/ko/common.js
+++ b/frontend/src/locales/ko/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -653,6 +654,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/nl/common.js b/frontend/src/locales/nl/common.js
index ec975e8ad5..8d05f90e9f 100644
--- a/frontend/src/locales/nl/common.js
+++ b/frontend/src/locales/nl/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -663,6 +664,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/pt_BR/common.js b/frontend/src/locales/pt_BR/common.js
index ea295acb54..b4923627fe 100644
--- a/frontend/src/locales/pt_BR/common.js
+++ b/frontend/src/locales/pt_BR/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -664,6 +665,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/ru/common.js b/frontend/src/locales/ru/common.js
index 20f6c62b00..429b7c3d4a 100644
--- a/frontend/src/locales/ru/common.js
+++ b/frontend/src/locales/ru/common.js
@@ -100,6 +100,7 @@ const TRANSLATIONS = {
"system-prompt-variables": "Переменные системного запроса",
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -708,6 +709,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/tr/common.js b/frontend/src/locales/tr/common.js
index db212a0056..72f473d482 100644
--- a/frontend/src/locales/tr/common.js
+++ b/frontend/src/locales/tr/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -663,6 +664,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/vn/common.js b/frontend/src/locales/vn/common.js
index 4f138e936d..5c35353564 100644
--- a/frontend/src/locales/vn/common.js
+++ b/frontend/src/locales/vn/common.js
@@ -92,6 +92,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -662,6 +663,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/zh/common.js b/frontend/src/locales/zh/common.js
index c31e9d02cb..2de892b13b 100644
--- a/frontend/src/locales/zh/common.js
+++ b/frontend/src/locales/zh/common.js
@@ -96,6 +96,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -641,6 +642,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/locales/zh_TW/common.js b/frontend/src/locales/zh_TW/common.js
index af689f48fb..d0b687a3c8 100644
--- a/frontend/src/locales/zh_TW/common.js
+++ b/frontend/src/locales/zh_TW/common.js
@@ -96,6 +96,7 @@ const TRANSLATIONS = {
"system-prompt-variables": null,
interface: null,
branding: null,
+ chat: null,
},
login: {
"multi-user": {
@@ -644,6 +645,18 @@ const TRANSLATIONS = {
title: null,
description: null,
},
+ chat: {
+ title: null,
+ description: null,
+ auto_submit: {
+ title: null,
+ description: null,
+ },
+ auto_speak: {
+ title: null,
+ description: null,
+ },
+ },
items: {
theme: {
title: null,
diff --git a/frontend/src/models/appearance.js b/frontend/src/models/appearance.js
index b8562c7392..a066bdfed6 100644
--- a/frontend/src/models/appearance.js
+++ b/frontend/src/models/appearance.js
@@ -1,7 +1,12 @@
import { APPEARANCE_SETTINGS } from "@/utils/constants";
const Appearance = {
- defaultSettings: { showScrollbar: false },
+ defaultSettings: {
+ showScrollbar: false,
+ autoSubmitSttInput: true,
+ autoPlayAssistantTtsResponse: false,
+ },
+
/**
* Fetches any locally storage settings for the user
* @returns {{showScrollbar: boolean}}
@@ -15,6 +20,31 @@ const Appearance = {
}
},
+ /**
+ * Fetches a specific setting from the user's settings
+ * @param {string} key - The key of the setting to fetch
+ * @returns {any} - a default value if the setting is not found or the current value
+ */
+ get: (key) => {
+ const settings = Appearance.getSettings();
+ return settings.hasOwnProperty(key)
+ ? settings[key]
+ : Appearance.defaultSettings[key];
+ },
+
+ /**
+ * Updates a specific setting from the user's settings
+ * @param {string} key - The key of the setting to update
+ * @param {any} value - The value to update the setting to
+ * @returns {object}
+ */
+ set: (key, value) => {
+ const settings = Appearance.getSettings();
+ settings[key] = value;
+ Appearance.updateSettings(settings);
+ return settings;
+ },
+
/**
* Updates locally stored user settings
* @param {object} newSettings - new settings to update.
diff --git a/frontend/src/pages/GeneralSettings/Settings/Chat/index.jsx b/frontend/src/pages/GeneralSettings/Settings/Chat/index.jsx
new file mode 100644
index 0000000000..1e3a056236
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/Settings/Chat/index.jsx
@@ -0,0 +1,34 @@
+import Sidebar from "@/components/SettingsSidebar";
+import { isMobile } from "react-device-detect";
+import { useTranslation } from "react-i18next";
+import AutoSubmit from "../components/AutoSubmit";
+import AutoSpeak from "../components/AutoSpeak";
+
+export default function ChatSettings() {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+
+
+ {t("customization.chat.title")}
+
+
+
+ {t("customization.chat.description")}
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/GeneralSettings/Settings/components/AutoSpeak/index.jsx b/frontend/src/pages/GeneralSettings/Settings/components/AutoSpeak/index.jsx
new file mode 100644
index 0000000000..3c4a7cf61b
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/Settings/components/AutoSpeak/index.jsx
@@ -0,0 +1,59 @@
+import React, { useState, useEffect } from "react";
+import Appearance from "@/models/appearance";
+import { useTranslation } from "react-i18next";
+
+export default function AutoSpeak() {
+ const [saving, setSaving] = useState(false);
+ const [autoPlayAssistantTtsResponse, setAutoPlayAssistantTtsResponse] =
+ useState(false);
+ const { t } = useTranslation();
+
+ const handleChange = async (e) => {
+ const newValue = e.target.checked;
+ setAutoPlayAssistantTtsResponse(newValue);
+ setSaving(true);
+ try {
+ Appearance.updateSettings({ autoPlayAssistantTtsResponse: newValue });
+ } catch (error) {
+ console.error("Failed to update appearance settings:", error);
+ setAutoPlayAssistantTtsResponse(!newValue);
+ }
+ setSaving(false);
+ };
+
+ useEffect(() => {
+ function fetchSettings() {
+ const settings = Appearance.getSettings();
+ setAutoPlayAssistantTtsResponse(
+ settings.autoPlayAssistantTtsResponse ?? false
+ );
+ }
+ fetchSettings();
+ }, []);
+
+ return (
+
+
+ {t("customization.chat.auto_speak.title")}
+
+
+ {t("customization.chat.auto_speak.description")}
+
+
+
+ );
+}
diff --git a/frontend/src/pages/GeneralSettings/Settings/components/AutoSubmit/index.jsx b/frontend/src/pages/GeneralSettings/Settings/components/AutoSubmit/index.jsx
new file mode 100644
index 0000000000..d406a23d3a
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/Settings/components/AutoSubmit/index.jsx
@@ -0,0 +1,56 @@
+import React, { useState, useEffect } from "react";
+import Appearance from "@/models/appearance";
+import { useTranslation } from "react-i18next";
+
+export default function AutoSubmit() {
+ const [saving, setSaving] = useState(false);
+ const [autoSubmitSttInput, setAutoSubmitSttInput] = useState(true);
+ const { t } = useTranslation();
+
+ const handleChange = async (e) => {
+ const newValue = e.target.checked;
+ setAutoSubmitSttInput(newValue);
+ setSaving(true);
+ try {
+ Appearance.updateSettings({ autoSubmitSttInput: newValue });
+ } catch (error) {
+ console.error("Failed to update appearance settings:", error);
+ setAutoSubmitSttInput(!newValue);
+ }
+ setSaving(false);
+ };
+
+ useEffect(() => {
+ function fetchSettings() {
+ const settings = Appearance.getSettings();
+ setAutoSubmitSttInput(settings.autoSubmitSttInput ?? true);
+ }
+ fetchSettings();
+ }, []);
+
+ return (
+
+
+ {t("customization.chat.auto_submit.title")}
+
+
+ {t("customization.chat.auto_submit.description")}
+
+
+
+ );
+}
diff --git a/frontend/src/utils/chat/index.js b/frontend/src/utils/chat/index.js
index abde54fe9c..27ea28eb5f 100644
--- a/frontend/src/utils/chat/index.js
+++ b/frontend/src/utils/chat/index.js
@@ -1,4 +1,5 @@
import { THREAD_RENAME_EVENT } from "@/components/Sidebar/ActiveWorkspaces/ThreadContainer";
+import { emitAssistantMessageCompleteEvent } from "@/components/contexts/TTSProvider";
export const ABORT_STREAM_EVENT = "abort-chat-stream";
// For handling of chat responses in the frontend by their various types.
@@ -81,6 +82,7 @@ export default function handleChat(
chatId,
metrics,
});
+ emitAssistantMessageCompleteEvent(chatId);
} else if (
type === "textResponseChunk" ||
type === "finalizeResponseStream"
@@ -102,6 +104,7 @@ export default function handleChat(
metrics,
};
setLoadingResponse(false);
+ emitAssistantMessageCompleteEvent(chatId);
} else {
updatedHistory = {
...existingHistory,
diff --git a/frontend/src/utils/paths.js b/frontend/src/utils/paths.js
index 61c2ea75f0..48c28141b3 100644
--- a/frontend/src/utils/paths.js
+++ b/frontend/src/utils/paths.js
@@ -134,6 +134,9 @@ export default {
agentSkills: () => {
return "/settings/agents";
},
+ chat: () => {
+ return "/settings/chat";
+ },
apiKeys: () => {
return "/settings/api-keys";
},