diff --git a/src/controller/chat_completion/mod.rs b/src/controller/chat_completion/mod.rs index c84c6df..04dae46 100644 --- a/src/controller/chat_completion/mod.rs +++ b/src/controller/chat_completion/mod.rs @@ -548,16 +548,49 @@ async fn handle_stage_speech_to_text_actual_transcribing( .instrument(span) .await?; - let transcribed_text = create_transcribed_message_text(&speech_to_text_result.text); + // Only use the `> 🦻 Transcribed text` format if we're posting in a thread. + // + // If we're dealing with a regular reply (which would be the case in "Transcribe-only mode" = speech-to-text/flow-type=only_transcribe), + // we don't want to use the `> 🦻 Transcribed text` format for 2 reasons: + // + // 1. This kind of blockquote-formatting can be confused by clients for a fallback-for-rich-replies + // (see https://spec.matrix.org/v1.11/client-server-api/#fallbacks-for-rich-replies). + // It makes certain clients render our messages incorrectly. + // + // 2. Transcribe-only mode is typically used for memos. Sticking to a plain-text format + // allows people to copy-paste the text or forward it to another room more easily (without having to strip formatting, etc.) + // + // When sending a bare reply, we'd better annotate the message with a 🦻 reaction instead, + // to make it clear to users that it's a transcription. + // + // Regardless of how we post this message, it will be posted as a notice, + // which can indicate to the bot (for potential future text-generation purposes) that this message is not a bot message. + let (transcribed_text, annotate_message_with_reaction) = if let MessageResponseType::InThread(_) = response_type { + (create_transcribed_message_text(&speech_to_text_result.text), false) + } else { + (speech_to_text_result.text, true) + }; let result = bot .messaging() .send_notice_markdown_no_fail(message_context.room(), transcribed_text, response_type) .await; - result + let event_id = result .map(|result| result.event_id) - .ok_or_else(|| anyhow::anyhow!("Failed to send transcribed text")) + .ok_or_else(|| anyhow::anyhow!("Failed to send transcribed text"))?; + + if annotate_message_with_reaction { + bot.reacting() + .react_no_fail( + message_context.room(), + event_id.clone(), + AgentPurpose::SpeechToText.emoji().to_owned(), + ) + .await; + } + + Ok(event_id) } async fn send_tts_offer_for_message( diff --git a/src/conversation/llm/utils.rs b/src/conversation/llm/utils.rs index 1071665..89c8296 100644 --- a/src/conversation/llm/utils.rs +++ b/src/conversation/llm/utils.rs @@ -31,6 +31,9 @@ fn convert_bot_notice_message(text: &str) -> Option { // Notice messages sent by the bot are usually transcriptions of previous messages sent by the user. // Such transcriptions are prefixed with an emoji and blockquoted. // If we find a notice that doesn't match this pattern, we skip it. + // + // It should be noted that transcriptions are sometimes posted as regular notice messages which do not include + // the `> 🦻` formatting. This function will not handle these properly. if let Some(text) = text_to_speech_utils::parse_transcribed_message_text(text) { // This is a transcription message. We remove the prefix and consider it as a message sent by the user. diff --git a/src/utils/text_to_speech.rs b/src/utils/text_to_speech.rs index 61fc068..0da0787 100644 --- a/src/utils/text_to_speech.rs +++ b/src/utils/text_to_speech.rs @@ -5,12 +5,18 @@ use super::text::{block_quote, block_unquote}; /// Creates a text message which is based on transcribed audio. /// This text message is prefixed with an emoji and blockquoted, to indicate that it is a transcription. /// To reverse the process, use `parse_transcribed_message_text()`. +/// +/// It should be noted that in certain cases (Transcribe-only mode), transcriptions are posted as regular notice messages which do not include +/// the `> 🦻` prefixing. That is, not every transcribed message will pass through here (intentionally). pub fn create_transcribed_message_text(text: &str) -> String { block_quote(&format!("{} {}", AgentPurpose::SpeechToText.emoji(), text)) } /// Parses a transcribed message text, reversing the process done by `create_transcribed_message_text()`. /// If the provided text string does not match the expected format, None is returned. +/// +/// It should be noted that in certain cases (Transcribe-only mode), transcriptions are posted as regular notice messages which do not include +/// the `> 🦻` prefixing. This function will not handle these properly. pub fn parse_transcribed_message_text(text: &str) -> Option { if !text.starts_with("> ") { return None;