diff --git a/app/brave_command_ids.h b/app/brave_command_ids.h index f888afeffdf..de1286e899e 100644 --- a/app/brave_command_ids.h +++ b/app/brave_command_ids.h @@ -101,6 +101,22 @@ // AI chat commands. #define IDC_AI_CHAT_CONTEXT_SUMMARIZE_TEXT 56226 #define IDC_AI_CHAT_CONTEXT_LEO_TOOLS 56227 +#define IDC_AI_CHAT_CONTEXT_EXPLAIN 56228 +#define IDC_AI_CHAT_CONTEXT_PARAPHRASE 56229 +#define IDC_AI_CHAT_CONTEXT_CREATE_TAGLINE 56230 +#define IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_POST 56231 +#define IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT 56232 +#define IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG 56233 +#define IDC_AI_CHAT_CONTEXT_CHANGE_LENGTH 56234 +#define IDC_AI_CHAT_CONTEXT_IMPROVE 56235 +#define IDC_AI_CHAT_CONTEXT_SIMPLIFY 56236 +#define IDC_AI_CHAT_CONTEXT_CHANGE_TONE 56237 +#define IDC_AI_CHAT_CONTEXT_ACADEMICIZE 56238 +#define IDC_AI_CHAT_CONTEXT_PROFESSIONALIZE 56239 +#define IDC_AI_CHAT_CONTEXT_CASUALIZE 56240 +#define IDC_AI_CHAT_CONTEXT_FUNNY_TONE 56241 +#define IDC_AI_CHAT_CONTEXT_SHORTEN 56242 +#define IDC_AI_CHAT_CONTEXT_EXPAND 56243 // Bookmark commands. #define IDC_TOGGLE_ALL_BOOKMARKS_BUTTON_VISIBILITY 56300 diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 443d6116f22..27d2c822f2c 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -224,13 +224,6 @@ More… - - Leo tools - - - Summarize - - Install and run Google Widevine diff --git a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 9db7f7baf06..51b1bab1511 100644 --- a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.cc @@ -46,7 +46,10 @@ #include "brave/browser/ui/sidebar/sidebar_controller.h" #include "brave/components/ai_chat/content/browser/ai_chat_tab_helper.h" #include "brave/components/ai_chat/core/browser/utils.h" +#include "brave/components/ai_chat/core/common/features.h" +#include "brave/components/ai_chat/core/common/mojom/ai_chat.mojom.h" #include "brave/components/ai_chat/core/common/pref_names.h" +#include "components/grit/brave_components_strings.h" #endif // Our .h file creates a masquerade for RenderViewContextMenu. Switch @@ -187,11 +190,16 @@ BraveRenderViewContextMenu::BraveRenderViewContextMenu( #endif #if BUILDFLAG(ENABLE_AI_CHAT) , - ai_chat_submenu_model_(this) + ai_chat_submenu_model_(this), + ai_chat_change_tone_submenu_model_(this), + ai_chat_change_length_submenu_model_(this), + ai_chat_social_media_post_submenu_model_(this) #endif { } +BraveRenderViewContextMenu::~BraveRenderViewContextMenu() = default; + bool BraveRenderViewContextMenu::IsCommandIdEnabled(int id) const { switch (id) { #if BUILDFLAG(ENABLE_TEXT_RECOGNITION) @@ -229,8 +237,24 @@ bool BraveRenderViewContextMenu::IsCommandIdEnabled(int id) const { return false; #endif #if BUILDFLAG(ENABLE_AI_CHAT) - case IDC_AI_CHAT_CONTEXT_LEO_TOOLS: case IDC_AI_CHAT_CONTEXT_SUMMARIZE_TEXT: + case IDC_AI_CHAT_CONTEXT_LEO_TOOLS: + case IDC_AI_CHAT_CONTEXT_EXPLAIN: + case IDC_AI_CHAT_CONTEXT_PARAPHRASE: + case IDC_AI_CHAT_CONTEXT_CREATE_TAGLINE: + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT: + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG: + case IDC_AI_CHAT_CONTEXT_IMPROVE: + case IDC_AI_CHAT_CONTEXT_SIMPLIFY: + case IDC_AI_CHAT_CONTEXT_CHANGE_TONE: + case IDC_AI_CHAT_CONTEXT_ACADEMICIZE: + case IDC_AI_CHAT_CONTEXT_PROFESSIONALIZE: + case IDC_AI_CHAT_CONTEXT_CASUALIZE: + case IDC_AI_CHAT_CONTEXT_FUNNY_TONE: + case IDC_AI_CHAT_CONTEXT_SHORTEN: + case IDC_AI_CHAT_CONTEXT_EXPAND: + case IDC_AI_CHAT_CONTEXT_CHANGE_LENGTH: + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_POST: return IsAIChatEnabled(); #endif default: @@ -324,6 +348,19 @@ void BraveRenderViewContextMenu::ExecuteCommand(int id, int event_flags) { #endif #if BUILDFLAG(ENABLE_AI_CHAT) case IDC_AI_CHAT_CONTEXT_SUMMARIZE_TEXT: + case IDC_AI_CHAT_CONTEXT_EXPLAIN: + case IDC_AI_CHAT_CONTEXT_PARAPHRASE: + case IDC_AI_CHAT_CONTEXT_CREATE_TAGLINE: + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT: + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG: + case IDC_AI_CHAT_CONTEXT_IMPROVE: + case IDC_AI_CHAT_CONTEXT_SIMPLIFY: + case IDC_AI_CHAT_CONTEXT_ACADEMICIZE: + case IDC_AI_CHAT_CONTEXT_PROFESSIONALIZE: + case IDC_AI_CHAT_CONTEXT_CASUALIZE: + case IDC_AI_CHAT_CONTEXT_FUNNY_TONE: + case IDC_AI_CHAT_CONTEXT_SHORTEN: + case IDC_AI_CHAT_CONTEXT_EXPAND: ExecuteAIChatCommand(id); break; #endif @@ -380,7 +417,63 @@ void BraveRenderViewContextMenu::ExecuteAIChatCommand(int command) { switch (command) { case IDC_AI_CHAT_CONTEXT_SUMMARIZE_TEXT: - helper->SummarizeSelectedText(base::UTF16ToUTF8(params_.selection_text)); + helper->SubmitSelectedText( + base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::SUMMARIZE_SELECTED_TEXT); + break; + case IDC_AI_CHAT_CONTEXT_EXPLAIN: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::EXPLAIN); + break; + case IDC_AI_CHAT_CONTEXT_PARAPHRASE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::PARAPHRASE); + break; + case IDC_AI_CHAT_CONTEXT_CREATE_TAGLINE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::CREATE_TAGLINE); + break; + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT: + helper->SubmitSelectedText( + base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::CREATE_SOCIAL_MEDIA_COMMENT_SHORT); + break; + case IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG: + helper->SubmitSelectedText( + base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::CREATE_SOCIAL_MEDIA_COMMENT_LONG); + break; + case IDC_AI_CHAT_CONTEXT_IMPROVE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::IMPROVE); + break; + case IDC_AI_CHAT_CONTEXT_SIMPLIFY: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::SIMPLIFY); + break; + case IDC_AI_CHAT_CONTEXT_ACADEMICIZE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::ACADEMICIZE); + break; + case IDC_AI_CHAT_CONTEXT_PROFESSIONALIZE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::PROFESSIONALIZE); + break; + case IDC_AI_CHAT_CONTEXT_CASUALIZE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::CASUALIZE); + break; + case IDC_AI_CHAT_CONTEXT_FUNNY_TONE: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::FUNNY_TONE); + break; + case IDC_AI_CHAT_CONTEXT_SHORTEN: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::SHORTEN); + break; + case IDC_AI_CHAT_CONTEXT_EXPAND: + helper->SubmitSelectedText(base::UTF16ToUTF8(params_.selection_text), + ai_chat::mojom::ActionType::EXPAND); break; default: NOTREACHED_NORETURN(); @@ -396,8 +489,65 @@ void BraveRenderViewContextMenu::BuildAIChatMenu() { if (!print_index.has_value()) { return; } + + ai_chat_submenu_model_.AddTitleWithStringId( + IDS_AI_CHAT_CONTEXT_QUICK_ACTIONS); ai_chat_submenu_model_.AddItemWithStringId( IDC_AI_CHAT_CONTEXT_SUMMARIZE_TEXT, IDS_AI_CHAT_CONTEXT_SUMMARIZE_TEXT); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_EXPLAIN, + IDS_AI_CHAT_CONTEXT_EXPLAIN); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_PARAPHRASE, + IDS_AI_CHAT_CONTEXT_PARAPHRASE); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_IMPROVE, + IDS_AI_CHAT_CONTEXT_IMPROVE); + ai_chat_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR); + + ai_chat_submenu_model_.AddTitleWithStringId(IDS_AI_CHAT_CONTEXT_REWRITE); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_PARAPHRASE, + IDS_AI_CHAT_CONTEXT_PARAPHRASE); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_IMPROVE, + IDS_AI_CHAT_CONTEXT_IMPROVE); + ai_chat_submenu_model_.AddItemWithStringId(IDC_AI_CHAT_CONTEXT_SIMPLIFY, + IDS_AI_CHAT_CONTEXT_SIMPLIFY); + + ai_chat_change_tone_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_ACADEMICIZE, IDS_AI_CHAT_CONTEXT_ACADEMICIZE); + ai_chat_change_tone_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_PROFESSIONALIZE, IDS_AI_CHAT_CONTEXT_PROFESSIONALIZE); + ai_chat_change_tone_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_CASUALIZE, IDS_AI_CHAT_CONTEXT_CASUALIZE); + ai_chat_change_tone_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_FUNNY_TONE, IDS_AI_CHAT_CONTEXT_FUNNY_TONE); + + ai_chat_submenu_model_.AddSubMenuWithStringId( + IDC_AI_CHAT_CONTEXT_CHANGE_TONE, IDS_AI_CHAT_CONTEXT_CHANGE_TONE, + &ai_chat_change_tone_submenu_model_); + + ai_chat_change_length_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_SHORTEN, IDS_AI_CHAT_CONTEXT_SHORTEN); + ai_chat_change_length_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_EXPAND, IDS_AI_CHAT_CONTEXT_EXPAND); + ai_chat_submenu_model_.AddSubMenuWithStringId( + IDC_AI_CHAT_CONTEXT_CHANGE_LENGTH, IDS_AI_CHAT_CONTEXT_CHANGE_LENGTH, + &ai_chat_change_length_submenu_model_); + + ai_chat_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR); + + ai_chat_submenu_model_.AddTitleWithStringId(IDS_AI_CHAT_CONTEXT_CREATE); + ai_chat_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_CREATE_TAGLINE, IDS_AI_CHAT_CONTEXT_CREATE_TAGLINE); + + ai_chat_social_media_post_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT, + IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT); + ai_chat_social_media_post_submenu_model_.AddItemWithStringId( + IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG, + IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG); + ai_chat_submenu_model_.AddSubMenuWithStringId( + IDC_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_POST, + IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_POST, + &ai_chat_social_media_post_submenu_model_); + menu_model_.InsertSubMenuWithStringIdAt( *print_index, IDC_AI_CHAT_CONTEXT_LEO_TOOLS, IDS_AI_CHAT_CONTEXT_LEO_TOOLS, &ai_chat_submenu_model_); diff --git a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.h index e99df9ec65f..901d1d8a0e3 100644 --- a/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.h +++ b/chromium_src/chrome/browser/renderer_context_menu/render_view_context_menu.h @@ -37,6 +37,7 @@ class BraveRenderViewContextMenu : public RenderViewContextMenu_Chromium { // NOLINTNEXTLINE(runtime/references) BraveRenderViewContextMenu(content::RenderFrameHost& render_frame_host, const content::ContextMenuParams& params); + ~BraveRenderViewContextMenu() override; // RenderViewContextMenuBase: bool IsCommandIdEnabled(int command_id) const override; void ExecuteCommand(int id, int event_flags) override; @@ -66,6 +67,9 @@ class BraveRenderViewContextMenu : public RenderViewContextMenu_Chromium { void BuildAIChatMenu(); ui::SimpleMenuModel ai_chat_submenu_model_; + ui::SimpleMenuModel ai_chat_change_tone_submenu_model_; + ui::SimpleMenuModel ai_chat_change_length_submenu_model_; + ui::SimpleMenuModel ai_chat_social_media_post_submenu_model_; #endif #if BUILDFLAG(ENABLE_TEXT_RECOGNITION) diff --git a/components/ai_chat/core/browser/constants.cc b/components/ai_chat/core/browser/constants.cc index a15992509aa..84469edf922 100644 --- a/components/ai_chat/core/browser/constants.cc +++ b/components/ai_chat/core/browser/constants.cc @@ -107,6 +107,27 @@ base::span GetLocalizedStrings() { {"contextToggleLabel", IDS_CHAT_UI_CONTEXT_TOGGLE_LABEL}, {"contextToggleTooltipInfo", IDS_CHAT_UI_CONTEXT_TOGGLE_TOOLTIP_INFO}, {"subscriptionPolicyInfo", IDS_CHAT_UI_SUBSCRIPTION_POLICY_INFO}, + {"explainLabel", IDS_AI_CHAT_CONTEXT_EXPLAIN}, + {"summarizeLabel", IDS_AI_CHAT_CONTEXT_SUMMARIZE_TEXT}, + {"paraphraseLabel", IDS_AI_CHAT_CONTEXT_PARAPHRASE}, + {"createCategoryTitle", IDS_AI_CHAT_CONTEXT_CREATE}, + {"taglineLabel", IDS_AI_CHAT_CONTEXT_CREATE_TAGLINE}, + {"socialMediaPostLabel", IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_POST}, + {"socialMediaShortLabel", + IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_SHORT}, + {"socialMediaLongLabel", + IDS_AI_CHAT_CONTEXT_CREATE_SOCIAL_MEDIA_COMMENT_LONG}, + {"rewriteCategoryTitle", IDS_AI_CHAT_CONTEXT_REWRITE}, + {"improveLabel", IDS_AI_CHAT_CONTEXT_IMPROVE}, + {"simplifyLabel", IDS_AI_CHAT_CONTEXT_SIMPLIFY}, + {"changeToneLabel", IDS_AI_CHAT_CONTEXT_CHANGE_TONE}, + {"changeLengthLabel", IDS_AI_CHAT_CONTEXT_CHANGE_LENGTH}, + {"academicizeLabel", IDS_AI_CHAT_CONTEXT_ACADEMICIZE}, + {"professionalizeLabel", IDS_AI_CHAT_CONTEXT_PROFESSIONALIZE}, + {"casualizeLabel", IDS_AI_CHAT_CONTEXT_CASUALIZE}, + {"funnyToneLabel", IDS_AI_CHAT_CONTEXT_FUNNY_TONE}, + {"shortenLabel", IDS_AI_CHAT_CONTEXT_SHORTEN}, + {"expandLabel", IDS_AI_CHAT_CONTEXT_EXPAND}, {"sendSiteHostnameLabel", IDS_CHAT_UI_SEND_SITE_HOSTNAME_LABEL}}; return kLocalizedStrings; diff --git a/components/ai_chat/core/browser/conversation_driver.cc b/components/ai_chat/core/browser/conversation_driver.cc index a2463ea1bb0..fe47b8a62aa 100644 --- a/components/ai_chat/core/browser/conversation_driver.cc +++ b/components/ai_chat/core/browser/conversation_driver.cc @@ -15,6 +15,7 @@ #include "base/containers/fixed_flat_set.h" #include "base/functional/bind.h" #include "base/memory/weak_ptr.h" +#include "base/no_destructor.h" #include "base/notreached.h" #include "base/one_shot_event.h" #include "base/ranges/algorithm.h" @@ -50,6 +51,48 @@ bool IsPremiumStatus(mojom::PremiumStatus status) { status == mojom::PremiumStatus::ActiveDisconnected; } +const base::flat_map& +GetActionTypeQuestionMap() { + static const base::NoDestructor< + base::flat_map> + map({{mojom::ActionType::SUMMARIZE_PAGE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_PAGE)}, + {mojom::ActionType::SUMMARIZE_VIDEO, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_VIDEO)}, + {mojom::ActionType::SUMMARIZE_SELECTED_TEXT, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_SUMMARIZE_SELECTED_TEXT)}, + {mojom::ActionType::EXPLAIN, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_EXPLAIN)}, + {mojom::ActionType::PARAPHRASE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_PARAPHRASE)}, + {mojom::ActionType::CREATE_TAGLINE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_CREATE_TAGLINE)}, + {mojom::ActionType::CREATE_SOCIAL_MEDIA_COMMENT_SHORT, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_CREATE_SOCIAL_MEDIA_COMMENT_SHORT)}, + {mojom::ActionType::CREATE_SOCIAL_MEDIA_COMMENT_LONG, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_CREATE_SOCIAL_MEDIA_COMMENT_LONG)}, + {mojom::ActionType::IMPROVE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_IMPROVE)}, + {mojom::ActionType::SIMPLIFY, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SIMPLIFY)}, + {mojom::ActionType::PROFESSIONALIZE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_PROFESSIONALIZE)}, + {mojom::ActionType::CASUALIZE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_CASUALIZE)}, + {mojom::ActionType::FUNNY_TONE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_FUNNY_TONE)}, + {mojom::ActionType::ACADEMICIZE, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_ACADEMICIZE)}, + {mojom::ActionType::SHORTEN, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SHORTEN)}, + {mojom::ActionType::EXPAND, + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_EXPAND)}}); + return *map; +} + } // namespace ConversationDriver::ConversationDriver( @@ -607,13 +650,15 @@ void ConversationDriver::MaybeUnlinkPageContent() { } } -void ConversationDriver::SummarizeSelectedText( - const std::string& selected_text) { - mojom::ConversationTurn turn = { - CharacterType::HUMAN, mojom::ActionType::SUMMARIZE_SELECTED_TEXT, - ConversationTurnVisibility::VISIBLE, - l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_SELECTED_TEXT), - selected_text}; +void ConversationDriver::SubmitSelectedText(const std::string& selected_text, + mojom::ActionType action_type) { + const auto& action_type_question_map = GetActionTypeQuestionMap(); + auto iter = action_type_question_map.find(action_type); + DCHECK(iter != action_type_question_map.end()); + + mojom::ConversationTurn turn = {CharacterType::HUMAN, action_type, + ConversationTurnVisibility::VISIBLE, + iter->second, selected_text}; SubmitHumanConversationEntry(turn); } @@ -672,24 +717,22 @@ void ConversationDriver::SubmitHumanConversationEntry( // TODO(petemill): Tokenize the summary question so that we // don't have to do this weird substitution. // TODO(jocelyn): Assigning turn.type below is a workaround for now since - // callers of SubmitHumanConversationEntry mojo API currently don't have + // callers of SubmitHumanConversationEntry mojo API currently don't have // action_type specified. - std::string question_part; - if (turn.text == l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_PAGE)) { - turn.action_type = mojom::ActionType::SUMMARIZE_PAGE; - question_part = - l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_PAGE); - } else if (turn.text == - l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_VIDEO)) { - turn.action_type = mojom::ActionType::SUMMARIZE_VIDEO; - question_part = - l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_VIDEO); - } else if (turn.action_type == mojom::ActionType::SUMMARIZE_SELECTED_TEXT) { - question_part = - l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_SELECTED_TEXT); - } else { - turn.action_type = mojom::ActionType::QUERY; - question_part = turn.text; + std::string question_part = turn.text; + if (turn.action_type == mojom::ActionType::UNSPECIFIED) { + if (turn.text == l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_PAGE)) { + turn.action_type = mojom::ActionType::SUMMARIZE_PAGE; + question_part = + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_PAGE); + } else if (turn.text == + l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_VIDEO)) { + turn.action_type = mojom::ActionType::SUMMARIZE_VIDEO; + question_part = + l10n_util::GetStringUTF8(IDS_AI_CHAT_QUESTION_SUMMARIZE_VIDEO); + } else { + turn.action_type = mojom::ActionType::QUERY; + } } auto history = chat_history_; diff --git a/components/ai_chat/core/browser/conversation_driver.h b/components/ai_chat/core/browser/conversation_driver.h index 975aa4b040a..dd28c2cb825 100644 --- a/components/ai_chat/core/browser/conversation_driver.h +++ b/components/ai_chat/core/browser/conversation_driver.h @@ -106,8 +106,8 @@ class ConversationDriver { mojom::SiteInfoPtr BuildSiteInfo(); bool HasPendingConversationEntry(); - // Used to summarize the selected text in the page. - void SummarizeSelectedText(const std::string& selected_text); + void SubmitSelectedText(const std::string& selected_text, + mojom::ActionType action_type); void RateMessage(bool is_liked, uint32_t turn_id, diff --git a/components/ai_chat/core/browser/conversation_driver_unittest.cc b/components/ai_chat/core/browser/conversation_driver_unittest.cc index 7874393fce6..2196542d630 100644 --- a/components/ai_chat/core/browser/conversation_driver_unittest.cc +++ b/components/ai_chat/core/browser/conversation_driver_unittest.cc @@ -100,8 +100,6 @@ class ConversationDriverUnitTest : public testing::Test { &url_loader_factory_); auto skus_service_getter = base::BindRepeating( []() { return mojo::PendingRemote(); }); - // set prefs::kDefaultModelKey to llama or claude first, then change model - // later conversation_driver_ = std::make_unique( &prefs_, &local_state_, nullptr, skus_service_getter, shared_url_loader_factory_, ""); @@ -119,7 +117,7 @@ class ConversationDriverUnitTest : public testing::Test { std::unique_ptr conversation_driver_; }; -TEST_F(ConversationDriverUnitTest, SummarizeSelectedText) { +TEST_F(ConversationDriverUnitTest, SubmitSelectedText) { bool is_page_content_linked = false; url_loader_factory_.SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) { @@ -158,8 +156,9 @@ TEST_F(ConversationDriverUnitTest, SummarizeSelectedText) { // Fired from OnEngineCompletionComplete. EXPECT_CALL(observer, OnAPIRequestInProgress(false)).Times(1); - conversation_driver_->SummarizeSelectedText( - "I have spoken."); + conversation_driver_->SubmitSelectedText( + "I have spoken.", + mojom::ActionType::SUMMARIZE_SELECTED_TEXT); task_environment_.RunUntilIdle(); testing::Mock::VerifyAndClearExpectations(&observer); @@ -172,10 +171,13 @@ TEST_F(ConversationDriverUnitTest, SummarizeSelectedText) { EXPECT_EQ( history, std::vector( - {mojom::ConversationTurn(mojom::CharacterType::HUMAN, - mojom::ActionType::SUMMARIZE_SELECTED_TEXT, - mojom::ConversationTurnVisibility::VISIBLE, - "Summarize this excerpt", "I have spoken."), + {mojom::ConversationTurn( + mojom::CharacterType::HUMAN, + mojom::ActionType::SUMMARIZE_SELECTED_TEXT, + mojom::ConversationTurnVisibility::VISIBLE, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_SUMMARIZE_SELECTED_TEXT), + "I have spoken."), mojom::ConversationTurn(mojom::CharacterType::ASSISTANT, mojom::ActionType::RESPONSE, mojom::ConversationTurnVisibility::VISIBLE, @@ -198,8 +200,9 @@ TEST_F(ConversationDriverUnitTest, SummarizeSelectedText) { // Fired from OnEngineCompletionComplete. EXPECT_CALL(observer, OnAPIRequestInProgress(false)).Times(1); - conversation_driver_->SummarizeSelectedText( - "I have spoken again."); + conversation_driver_->SubmitSelectedText( + "I have spoken again.", + mojom::ActionType::SUMMARIZE_SELECTED_TEXT); task_environment_.RunUntilIdle(); testing::Mock::VerifyAndClearExpectations(&observer); @@ -211,19 +214,24 @@ TEST_F(ConversationDriverUnitTest, SummarizeSelectedText) { EXPECT_EQ( history2, std::vector( - {mojom::ConversationTurn(mojom::CharacterType::HUMAN, - mojom::ActionType::SUMMARIZE_SELECTED_TEXT, - mojom::ConversationTurnVisibility::VISIBLE, - "Summarize this excerpt", "I have spoken."), + {mojom::ConversationTurn( + mojom::CharacterType::HUMAN, + mojom::ActionType::SUMMARIZE_SELECTED_TEXT, + mojom::ConversationTurnVisibility::VISIBLE, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_SUMMARIZE_SELECTED_TEXT), + "I have spoken."), mojom::ConversationTurn(mojom::CharacterType::ASSISTANT, mojom::ActionType::RESPONSE, mojom::ConversationTurnVisibility::VISIBLE, "This is the way.", std::nullopt), - mojom::ConversationTurn(mojom::CharacterType::HUMAN, - mojom::ActionType::SUMMARIZE_SELECTED_TEXT, - mojom::ConversationTurnVisibility::VISIBLE, - "Summarize this excerpt", - "I have spoken again."), + mojom::ConversationTurn( + mojom::CharacterType::HUMAN, + mojom::ActionType::SUMMARIZE_SELECTED_TEXT, + mojom::ConversationTurnVisibility::VISIBLE, + l10n_util::GetStringUTF8( + IDS_AI_CHAT_QUESTION_SUMMARIZE_SELECTED_TEXT), + "I have spoken again."), mojom::ConversationTurn(mojom::CharacterType::ASSISTANT, mojom::ActionType::RESPONSE, mojom::ConversationTurnVisibility::VISIBLE, diff --git a/components/ai_chat/core/browser/engine/engine_consumer_claude_unittest.cc b/components/ai_chat/core/browser/engine/engine_consumer_claude_unittest.cc index 49cc6634e88..68a90f55d0c 100644 --- a/components/ai_chat/core/browser/engine/engine_consumer_claude_unittest.cc +++ b/components/ai_chat/core/browser/engine/engine_consumer_claude_unittest.cc @@ -81,13 +81,13 @@ TEST_F(EngineConsumerClaudeUnitTest, TestGenerateAssistantResponse) { "coding-related words and triple backticks along with language keyword " "(```language```) to wrap blocks of code or data.\n\nHere is the " "conversational history (between the user and you) prior to the " - "question.\n\n\nH: Which show is this catchphrase " + "request.\n\n\nH: Which show is this catchphrase " "from?\nSelected text: I have spoken.\n\nA: The " "Mandalorian.\n\n\nHere is an excerpt of the page content in " " tags:\n\nI'm groot.\n\n\nThe user selects " - "this excerpt from the page content.\n\nHere is the user's question " - "about the excerpt:\n\nWho?\n\n\nHow do you respond " - "to the user's question? Put your response in " + "this excerpt from the page content.\n\nHere is the user's request " + "about the excerpt:\n\nWho?\n\n\nHow do you respond " + "to the user's request? Put your response in " "tags.\n\nAssistant: \n"; base::RunLoop run_loop; @@ -129,7 +129,7 @@ TEST_F(EngineConsumerClaudeUnitTest, TestGenerateAssistantResponse) { std::move(callback).Run(""); }); engine_->GenerateAssistantResponse( - false, "12345", "12345", history, "user question", base::DoNothing(), + false, "12345", "12345", history, "user request", base::DoNothing(), base::BindLambdaForTesting( [&run_loop2](EngineConsumer::GenerationResult) { run_loop2.Quit(); @@ -147,8 +147,8 @@ TEST_F(EngineConsumerClaudeUnitTest, TestGenerateAssistantResponse) { ""); base::ReplaceFirstSubstringAfterOffset( &prompt_after_time_and_date, 0u, - "Here is the user's question about the excerpt", - "Here is the user's question"); + "Here is the user's request about the excerpt", + "Here is the user's request"); base::RunLoop run_loop3; EXPECT_CALL(*mock_remote_completion_client, QueryPrompt(_, _, _, _)) diff --git a/components/ai_chat/core/browser/engine/engine_consumer_llama_unittest.cc b/components/ai_chat/core/browser/engine/engine_consumer_llama_unittest.cc index 29d904b22c1..1313929e52d 100644 --- a/components/ai_chat/core/browser/engine/engine_consumer_llama_unittest.cc +++ b/components/ai_chat/core/browser/engine/engine_consumer_llama_unittest.cc @@ -74,12 +74,12 @@ TEST_F(EngineConsumerLlamaUnitTest, TestGenerateAssistantResponse) { "information.\n\nUse unicode symbols for formatting where appropriate. " "Use backticks (`) to wrap inline coding-related words and triple " "backticks along with language keyword (```language```) to wrap blocks " - "of code or data.\n<>\n\nThis is the text of a web page within " - " tags:\n\n This is a page. \n\nWhich show is this " + "of code or data.\n<>\n\nThis is the text of a web " + "page:\n\nThis is a page.\n\n\nWhich show is this " "catchphrase from?\nSelected text: This is the way. [/INST] The " - "Mandalorian.[INST] This is an excerpt of the page content in " - " tags:\n\n I'm groot. \n\nWhat's his name? " - "[/INST]"; + "Mandalorian.[INST] This is an excerpt of the page " + "content:\n\nI'm groot.\n\n\nWhat's his name? [/INST]"; + base::RunLoop run_loop; EXPECT_CALL(*mock_remote_completion_client, QueryPrompt(_, _, _, _)) .WillOnce([&](const std::string& prompt, @@ -99,12 +99,22 @@ TEST_F(EngineConsumerLlamaUnitTest, TestGenerateAssistantResponse) { testing::Mock::VerifyAndClearExpectations(mock_remote_completion_client); prompt_after_time_and_date = + "\n\nYour name is Leo, a helpful, respectful and honest AI assistant " + "created by the company Brave. You will be replying to a user of the " + "Brave browser. Always respond in a neutral tone. Be polite and " + "courteous. Answer concisely in no more than 50-80 words.\n\nPlease " + "ensure that your responses are socially unbiased and positive in " + "nature. If a question does not make any sense, or is not factually " + "coherent, explain why instead of answering something not correct. If " + "you don't know the answer to a question, please don't share false " + "information.\n\nUse unicode symbols for formatting where appropriate. " "Use backticks (`) to wrap inline coding-related words and triple " "backticks along with language keyword (```language```) to wrap blocks " - "of code or data.\n<>\n\nThis is the text of a web page within " - " tags:\n\n This is a page. \n\nThis is an excerpt " - "of the page content in tags:\n\n I'm groot. " - "\n\nWhat's his name? [/INST] "; + "of code or data.\n<>\n\nThis is the text of a web " + "page:\n\nThis is a page.\n\n\nThis is an excerpt of the " + "page content:\n\nI'm groot.\n\n\nWhat's his name? " + "[/INST] "; + base::RunLoop run_loop2; EXPECT_CALL(*mock_remote_completion_client, QueryPrompt(_, _, _, _)) .WillOnce([&](const std::string& prompt, @@ -133,14 +143,13 @@ TEST_F(EngineConsumerLlamaUnitTest, TestGenerateAssistantResponse) { EngineConsumer::GenerationCompletedCallback callback, EngineConsumer::GenerationDataCallback data_callback) { std::string prompt_segment_with_truncated_page_content = - "This is the text of a web page within tags:\n\n 12 " - "\n\n"; + "This is the text of a web page:\n\n12\n\n\n"; EXPECT_NE(prompt.find(prompt_segment_with_truncated_page_content), std::string::npos); std::string prompt_segment_with_truncated_selected_text = - "This is an excerpt of the page content in " - "tags:\n\n 12345 \n\n"; + "This is an excerpt of the page " + "content:\n\n12345\n\n\n"; EXPECT_NE(prompt.find(prompt_segment_with_truncated_selected_text), std::string::npos); std::move(callback).Run(""); diff --git a/components/ai_chat/core/common/mojom/ai_chat.mojom b/components/ai_chat/core/common/mojom/ai_chat.mojom index 6010930495f..e601b7c56be 100644 --- a/components/ai_chat/core/common/mojom/ai_chat.mojom +++ b/components/ai_chat/core/common/mojom/ai_chat.mojom @@ -86,6 +86,19 @@ enum ActionType { SUMMARIZE_VIDEO, SUMMARIZE_SELECTED_TEXT, QUERY, + EXPLAIN, + PARAPHRASE, + CREATE_TAGLINE, + CREATE_SOCIAL_MEDIA_COMMENT_SHORT, + CREATE_SOCIAL_MEDIA_COMMENT_LONG, + IMPROVE, + SIMPLIFY, + ACADEMICIZE, + PROFESSIONALIZE, + CASUALIZE, + FUNNY_TONE, + SHORTEN, + EXPAND, }; // Represents a single turn in a conversation. diff --git a/components/ai_chat/resources/page/components/action_type_label/index.tsx b/components/ai_chat/resources/page/components/action_type_label/index.tsx new file mode 100644 index 00000000000..fd5d9d52480 --- /dev/null +++ b/components/ai_chat/resources/page/components/action_type_label/index.tsx @@ -0,0 +1,109 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import Icon from '@brave/leo/react/icon' +import * as mojom from '../../api/page_handler' +import styles from './style.module.scss' +import { getLocale } from '$web-common/locale' + +interface ActionTypeLabelProps { + actionType: mojom.ActionType +} + +function getCategoryAndItem(actionType: mojom.ActionType): { + category: string | undefined, item: string | undefined +} { + switch (actionType) { + case mojom.ActionType.SUMMARIZE_SELECTED_TEXT: + return { category: undefined, item: getLocale('summarizeLabel')} + case mojom.ActionType.EXPLAIN: + return { category: undefined, item: getLocale('explainLabel')} + case mojom.ActionType.CREATE_TAGLINE: + return { + category: getLocale('createCategoryTitle'), + item: getLocale('taglineLabel') + } + case mojom.ActionType.CREATE_SOCIAL_MEDIA_COMMENT_SHORT: + return { + category: getLocale('socialMediaPostLabel'), + item: getLocale('socialMediaShortLabel') + } + case mojom.ActionType.CREATE_SOCIAL_MEDIA_COMMENT_LONG: + return { + category: getLocale('socialMediaPostLabel'), + item: getLocale('socialMediaLongLabel') + } + case mojom.ActionType.PARAPHRASE: + return { + category: getLocale('rewriteCategoryTitle'), + item: getLocale('paraphraseLabel') + } + case mojom.ActionType.IMPROVE: + return { + category: getLocale('rewriteCategoryTitle'), + item: getLocale('improveLabel') + } + case mojom.ActionType.SIMPLIFY: + return { + category: getLocale('rewriteCategoryTitle'), + item: getLocale('simplifyLabel') + } + case mojom.ActionType.ACADEMICIZE: + return { + category: getLocale('changeToneLabel'), + item: getLocale('academicizeLabel') + } + case mojom.ActionType.PROFESSIONALIZE: + return { + category: getLocale('changeToneLabel'), + item: getLocale('professionalizeLabel') + } + case mojom.ActionType.CASUALIZE: + return { + category: getLocale('changeToneLabel'), + item: getLocale('casualizeLabel') + } + case mojom.ActionType.FUNNY_TONE: + return { + category: getLocale('changeToneLabel'), + item: getLocale('funnyToneLabel') + } + case mojom.ActionType.SHORTEN: + return { + category: getLocale('changeLengthLabel'), + item: getLocale('shortenLabel') + } + case mojom.ActionType.EXPAND: + return { + category: getLocale('changeLengthLabel'), + item: getLocale('expandLabel') + } + default: + return { category: undefined, item: undefined } + } +} + +function ActionTypeLabel (props: ActionTypeLabelProps) { + const { category, item } = getCategoryAndItem(props.actionType) + + if (category && item) { + return ( +
+ {category} + + {item} +
+ ) + } + + return ( +
+ {item} +
+ ) +} + +export default ActionTypeLabel diff --git a/components/ai_chat/resources/page/components/action_type_label/style.module.scss b/components/ai_chat/resources/page/components/action_type_label/style.module.scss new file mode 100644 index 00000000000..5308998b803 --- /dev/null +++ b/components/ai_chat/resources/page/components/action_type_label/style.module.scss @@ -0,0 +1,25 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// you can obtain one at https://mozilla.org/MPL/2.0/. + +.actionTypeLabel { + --leo-icon-size: 14px; + --leo-icon-color: var(--leo-color-primary-50); + display: inline-flex; + flex-direction: row; + align-items: center; + padding: 0px 4px; + width: fit-content; + height: 20px; + background: var(--leo-color-primary-20); + border-radius: 4px; +} + +.text { + font: var(--leo-font-components-label); + display: inline-flex; + align-items: center; + text-transform: uppercase; + color: var(--leo-color-primary-50); +} diff --git a/components/ai_chat/resources/page/components/conversation_list/index.tsx b/components/ai_chat/resources/page/components/conversation_list/index.tsx index e809620c4c2..ff5348be1b4 100644 --- a/components/ai_chat/resources/page/components/conversation_list/index.tsx +++ b/components/ai_chat/resources/page/components/conversation_list/index.tsx @@ -16,6 +16,7 @@ import ContextMenuAssistant from '../context_menu_assistant' import { getLocale } from '$web-common/locale' import SiteTitle from '../site_title' import Quote from '../quote' +import ActionTypeLabel from '../action_type_label' const CodeBlock = React.lazy(async () => ({ default: (await import('../code_block')).default.Block })) const CodeInline = React.lazy(async () => ({ default: (await import('../code_block')).default.Inline })) @@ -168,7 +169,10 @@ function ConversationList(props: ConversationListProps) {
- {} + {!turn.selectedText && + } + {turn.selectedText && + } {isLoading && } {turn.selectedText && } {showSiteTitle &&
} diff --git a/components/ai_chat/resources/page/components/quote/style.module.scss b/components/ai_chat/resources/page/components/quote/style.module.scss index 56a0eb612ad..019332564f9 100644 --- a/components/ai_chat/resources/page/components/quote/style.module.scss +++ b/components/ai_chat/resources/page/components/quote/style.module.scss @@ -15,25 +15,24 @@ .text::before { content: ""; + position: absolute; + top: 0; + left: 0; width: 3px; + height: 100%; background: var(--leo-color-divider-strong); border-radius: 2px; - margin-right: 12px; - flex: none; - order: 0; - align-self: stretch; - flex-grow: 0; } .text { width: 100%; - display: flex; - align-items: center; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; + word-wrap: break-word; + position: relative; + padding-left: 18px; letter-spacing: -0.1px; color: var(--leo-color-text-secondary); - flex: none; - order: 1; - align-self: stretch; - flex-grow: 1; } - diff --git a/components/ai_chat/resources/page/stories/components_panel.tsx b/components/ai_chat/resources/page/stories/components_panel.tsx index 929a08d1954..95d66ffffb7 100644 --- a/components/ai_chat/resources/page/stories/components_panel.tsx +++ b/components/ai_chat/resources/page/stories/components_panel.tsx @@ -25,21 +25,21 @@ const HISTORY: mojom.ConversationTurn[] = [ characterType: mojom.CharacterType.HUMAN, visibility: mojom.ConversationTurnVisibility.VISIBLE, actionType: mojom.ActionType.UNSPECIFIED, - selectedText: '' + selectedText: undefined }, { text: 'Hi, How are you?', characterType: mojom.CharacterType.ASSISTANT, visibility: mojom.ConversationTurnVisibility.VISIBLE, actionType: mojom.ActionType.UNSPECIFIED, - selectedText: '' + selectedText: undefined }, { text: 'What is pointer compression?', characterType: mojom.CharacterType.HUMAN, actionType: mojom.ActionType.QUERY, visibility: mojom.ConversationTurnVisibility.VISIBLE, - selectedText: 'Pointer compression is a memory optimization technique where pointers (memory addresses) are stored in a compressed format to save memory.' + selectedText: undefined }, { text: 'Pointer compression is a memory optimization technique where pointers (memory addresses) are stored in a compressed format to save memory. The basic idea is that since most pointers will be clustered together and point to objects allocated around the same time, you can store a compressed representation of the pointer and decompress it when needed. Some common ways this is done: Store an offset from a base pointer instead of the full pointer value Store increments/decrements from the previous pointer instead of the full value Use pointer tagging to store extra information in the low bits of the pointer Encode groups of pointers together The tradeoff is some extra CPU cost to decompress the pointers, versus saving memory. This technique is most useful in memory constrained environments.', @@ -90,6 +90,20 @@ const HISTORY: mojom.ConversationTurn[] = [ visibility: mojom.ConversationTurnVisibility.VISIBLE, selectedText: undefined }, + { + text: 'Shorten this selected text', + characterType: mojom.CharacterType.HUMAN, + actionType: mojom.ActionType.SHORTEN, + visibility: mojom.ConversationTurnVisibility.VISIBLE, + selectedText: 'Pointer compression is a memory optimization technique where pointers are stored in a compressed format to save memory.' + }, + { + text: 'Pointer compression is a memory optimization technique.', + characterType: mojom.CharacterType.ASSISTANT, + actionType: mojom.ActionType.UNSPECIFIED, + visibility: mojom.ConversationTurnVisibility.VISIBLE, + selectedText: undefined + } ] const MODELS: mojom.Model[] = [ diff --git a/components/ai_chat/resources/page/stories/locale.ts b/components/ai_chat/resources/page/stories/locale.ts index d8547c5bcb9..37f5108f41f 100644 --- a/components/ai_chat/resources/page/stories/locale.ts +++ b/components/ai_chat/resources/page/stories/locale.ts @@ -87,4 +87,7 @@ provideStrings({ contextToggleLabel: 'Use page context for response', contextToggleTooltipInfo: 'Toggle on to ask about this page. It\'s content will be sent to Brave Leo along with your messages.', subscriptionPolicyInfo: 'All subscriptions are auto-renewed but can be cancelled at any time before renewal.', + summarizeLabel: 'Summarize', + changeLengthLabel: 'Change length', + shortenLabel: 'Shorten', }) diff --git a/components/resources/ai_chat_prompts.grdp b/components/resources/ai_chat_prompts.grdp index 990b0c5961b..005a62c2390 100644 --- a/components/resources/ai_chat_prompts.grdp +++ b/components/resources/ai_chat_prompts.grdp @@ -18,21 +18,21 @@ Here are some important rules for the interaction: -Here is the user's question: -<question> +Here is the user's request: +<request> $1 -</question> +</request> -Here is the user's question about the excerpt: -<question> +Here is the user's request about the excerpt: +<request> $1 -</question> +</request> -How do you respond to the user's question? Put your response in <response></response> tags. +How do you respond to the user's request? Put your response in <response></response> tags. Here is the text of a web page in <page> tags: <page> @@ -57,7 +57,7 @@ The user selects this excerpt from the page content. A user is watching this video. -Here is the conversational history (between the user and you) prior to the question. +Here is the conversational history (between the user and you) prior to the request. <history> $1 </history> @@ -66,8 +66,21 @@ Here is the conversational history (between the user and you) prior to the quest Propose up to 3 very short questions that a reader may ask about the content. Consider intriguing or unusual elements of the content, or structurally important. Separate each suggested question with the character "|". End the question list with a </response> tag. Provide a concise list of up to 6 bullets on the most important points of the page. -Summarize the excerpt +Generate a summary of the excerpt. Provide a concise list of up to 6 bullets of the most important points of the video. +Explain the excerpt in simple terms. Expand on concepts that might not be familiar to the user. +Rewrite the excerpt by paraphrasing. Include only the rewritten version in your response. +Use the excerpt to generate a tagline. +Use the excerpt to generate a post that could be used on social platforms like Twitter. +Use the excerpt to generate a post that could be used on social platforms like Reddit. +Improve the language of the excerpt. Include only the rewritten version in your response. +Rewrite the excerpt in simpler terms so that it is easier to understand for a general audience. Include only the rewritten version in your response. +Rewrite the excerpt in an academic tone. Include only the rewritten version in your response. +Rewrite the excerpt in a professional tone. Include only the rewritten version in your response. +Rewrite the excerpt in a casual tone. Include only the rewritten version in your response. +Rewrite the excerpt in a funny tone. Include only the rewritten version in your response. +Generate a shortened version of the excerpt in paragraph format by removing unnecessary details and refining the language for brevity. Include only the rewritten version in your response. +Generate a lengthened version of the excerpt in paragraph format by expanding on the details provided and adding more descriptive information where applicable. Include only the rewritten version in your response. The current time and date is $1 @@ -83,15 +96,17 @@ Use unicode symbols for formatting where appropriate. Use backticks (`) to wrap Here is your response: -This is an excerpt of the page content in <excerpt> tags: - -<excerpt> $1 </excerpt> +This is an excerpt of the page content: +<excerpt> +$1 +</excerpt> -This is the text of a web page within <page> tags: - -<page> $1 </page> +This is the text of a web page: +<page> +$1 +</page> $2 diff --git a/components/resources/ai_chat_ui_strings.grdp b/components/resources/ai_chat_ui_strings.grdp index 0bc726794ad..aeb635b23b9 100644 --- a/components/resources/ai_chat_ui_strings.grdp +++ b/components/resources/ai_chat_ui_strings.grdp @@ -36,9 +36,6 @@ Summarize this page - - Summarize this excerpt - Disconnect to stop sending this page content to Leo, and start a new conversation @@ -267,4 +264,70 @@ Share the hostname of the page you are on ($1www.example.com) to help us make Leo better. + + Leo tools + + + Quick actions + + + Create + + + Rewrite + + + Summarize + + + Short + + + Long + + + Blog post + + + Tagline + + + Paraphrase + + + Explain + + + Improve + + + Simplify + + + Change tone + + + Professional + + + Academic + + + Casual + + + Funny + + + Shorten + + + Expand + + + Change length + + + Social media post +