Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions front/src/actions/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ function createActions(store) {
currentMessageTextInput: e.target.value
});
},
setMessageTextInput(state, text) {
store.setState({
currentMessageTextInput: text
});
},
syncMessage(state, message) {
let newMessages = store.getState().messages;
// Check if message is already in the list
Expand Down
11 changes: 11 additions & 0 deletions front/src/config/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -5708,6 +5708,17 @@
"auto": "Auto",
"priceLegend": "€ günstig · €€ mittel · €€€ premium"
},
"voiceInput": {
"startListening": "Nachricht diktieren",
"stopListening": "Diktat beenden",
"error": "Die Spracherkennung ist fehlgeschlagen. Bitte versuche es erneut.",
"errorNoSpeech": "Keine Stimme erkannt. Prüfe, ob dein Mikrofon aktiviert ist, und versuche es erneut.",
"errorPermissionDenied": "Der Mikrofonzugriff wurde verweigert. Erlaube ihn in den Einstellungen deines Browsers, um eine Nachricht zu diktieren.",
"errorNoMicrophone": "Kein Mikrofon erkannt. Schließe eines an oder aktiviere es in den Systemeinstellungen.",
"errorNetwork": "Die Spracherkennung ist nicht verfügbar, dein Browser konnte seinen Sprachdienst nicht erreichen.",
"errorNotSupported": "Spracherkennung ist in diesem Browser nicht verfügbar.",
"browserTranscriptionNotice": "Wenn du eine Nachricht diktierst, transkribiert dein Browser, was du sagst: Gladys nimmt kein Audio auf und lädt keines hoch. Je nach Browser kann das Audio auf deinem Gerät verarbeitet oder an den eigenen Spracherkennungsdienst des Browsers gesendet werden."
},
"sidebar": {
"title": "Wie funktioniert der Chat?",
"intro": "Der Gladys-Chat nutzt die Gladys-Plus-Künstliche Intelligenz, damit du natürlich mit deinem vernetzten Zuhause kommunizieren kannst.",
Expand Down
11 changes: 11 additions & 0 deletions front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5719,6 +5719,17 @@
"label": "AI model",
"auto": "Auto",
"priceLegend": "€ cheap · €€ mid · €€€ premium"
},
"voiceInput": {
"startListening": "Dictate a message",
"stopListening": "Stop dictation",
"error": "Speech recognition failed. Please try again.",
"errorNoSpeech": "No voice detected. Check that your microphone is enabled, then try again.",
"errorPermissionDenied": "Microphone access was denied. Allow it in your browser settings to dictate a message.",
"errorNoMicrophone": "No microphone detected. Plug one in or enable it in system settings.",
"errorNetwork": "Speech recognition is unavailable, your browser could not reach its speech service.",
"errorNotSupported": "Speech recognition is not available in this browser.",
"browserTranscriptionNotice": "If you dictate a message, your browser transcribes what you say: Gladys neither records nor uploads any audio. Depending on your browser, the audio may be processed on your device or sent to your browser's own speech recognition service."
}
},
"history": {
Expand Down
11 changes: 11 additions & 0 deletions front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -5719,6 +5719,17 @@
"label": "Modèle IA",
"auto": "Auto",
"priceLegend": "€ économique · €€ moyen · €€€ premium"
},
"voiceInput": {
"startListening": "Dicter un message",
"stopListening": "Arrêter la dictée",
"error": "La reconnaissance vocale a échoué. Veuillez réessayer.",
"errorNoSpeech": "Aucune voix détectée. Vérifiez que votre micro est activé, puis réessayez.",
"errorPermissionDenied": "L'accès au micro a été refusé. Autorisez-le dans les réglages de votre navigateur pour dicter un message.",
"errorNoMicrophone": "Aucun micro détecté. Branchez ou activez un micro dans les réglages système.",
"errorNetwork": "La reconnaissance vocale est indisponible, votre navigateur n'a pas pu joindre son service vocal.",
"errorNotSupported": "La reconnaissance vocale n'est pas disponible dans ce navigateur.",
"browserTranscriptionNotice": "Si vous dictez un message, c'est votre navigateur qui transcrit ce que vous dites : Gladys n'enregistre et n'envoie aucun audio. Selon votre navigateur, l'audio peut être traité sur votre appareil ou envoyé au service de reconnaissance vocale de votre navigateur."
}
},
"history": {
Expand Down
44 changes: 42 additions & 2 deletions front/src/routes/chat/ChatPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { useEffect, useRef, useState } from 'preact/hooks';
import { connect } from 'unistore/preact';
import actions from '../../actions/message';
import { RequestStatus } from '../../utils/consts';
import { isSpeechRecognitionSupported } from '../../utils/speechRecognition';
import ChatItems from './ChatItems';
import EmptyChat from './EmptyChat';
import AiModelSelector from './AiModelSelector';
import ChatVoiceInputButton from './ChatVoiceInputButton';
import style from './style.css';

const IntegrationPage = connect(
Expand All @@ -19,14 +21,24 @@ const IntegrationPage = connect(
MessageGetStatus,
currentMessageTextInput,
updateMessageTextInput,
setMessageTextInput,
onKeyPress,
sendMessage,
gladysIsTyping,
httpClient
}) => {
const textareaRef = useRef(null);
const voiceInputRef = useRef(null);
const [selectedModel, setSelectedModel] = useState('auto');
const [gladysPlusConfigured, setGladysPlusConfigured] = useState(null);
const [voiceInputError, setVoiceInputError] = useState(null);
// While the microphone is on, the transcription rewrites the whole input:
// the textarea is read-only so an edit cannot be overwritten by the next
// interim result.
const [voiceInputListening, setVoiceInputListening] = useState(false);
// Browsers without the Web Speech API (Firefox for example) simply don't
// get a microphone button.
const [voiceInputSupported] = useState(isSpeechRecognitionSupported);
const hasMessageToSend = Boolean(currentMessageTextInput && currentMessageTextInput.trim().length > 0);

useEffect(() => {
Expand Down Expand Up @@ -63,13 +75,16 @@ const IntegrationPage = connect(
};

const handleSendMessage = () => {
if (voiceInputRef.current) {
voiceInputRef.current.cancelListening();
}
sendMessage(selectedModel);
};

const handleKeyPress = e => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage(selectedModel);
handleSendMessage();
return;
}
onKeyPress(e);
Expand Down Expand Up @@ -109,13 +124,26 @@ const IntegrationPage = connect(
<textarea
ref={textareaRef}
rows="1"
class={cx('form-control', style.chatInput)}
class={cx('form-control', style.chatInput, {
[style.chatInputWithVoice]: voiceInputSupported
})}
placeholder={<Text id="chat.messagePlaceholder" />}
value={currentMessageTextInput}
readOnly={voiceInputListening}
onInput={onComposerInput}
onKeyPress={handleKeyPress}
/>
</Localizer>
{voiceInputSupported && (
<ChatVoiceInputButton
ref={voiceInputRef}
language={user && user.language}
currentText={currentMessageTextInput}
onTranscript={setMessageTextInput}
onError={setVoiceInputError}
onListeningChange={setVoiceInputListening}
/>
)}
<button
type="button"
class={cx('btn', style.sendButton, {
Expand All @@ -128,6 +156,18 @@ const IntegrationPage = connect(
<i class="fe fe-send" />
</button>
</div>
{voiceInputSupported && (
// Shown as soon as the microphone button is available, so the user
// knows where the audio goes before starting a dictation.
<p class={style.voiceInputNotice}>
<Text id="chat.voiceInput.browserTranscriptionNotice" />
</p>
)}
{voiceInputError && (
<p class={style.voiceInputError}>
<Text id={`chat.voiceInput.${voiceInputError}`} />
</p>
)}
</div>
</div>
</div>
Expand Down
Loading
Loading