Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AIChat: Add Welcome guide as a new opt-in UX #20750

Closed
wants to merge 2 commits into from
Closed

Conversation

nullhook
Copy link
Contributor

@nullhook nullhook commented Oct 30, 2023

Resolves brave/brave-browser#33942

This PR introduces a new welcome guide for users who haven't agreed to the policy terms. Once the user has viewed and accepted the policy, the welcome guide will no longer be displayed.

Submitter Checklist:

  • I confirm that no security/privacy review is needed and no other type of reviews are needed, or that I have requested them
  • There is a ticket for my issue
  • Used Github auto-closing keywords in the PR description above
  • Wrote a good PR/commit description
  • Squashed any review feedback or "fixup" commits before merge, so that history is a record of what happened in the repo, not your PR
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally:
    • npm run test -- brave_browser_tests, npm run test -- brave_unit_tests wiki
    • npm run lint, npm run presubmit wiki, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed)

Reviewer Checklist:

  • A security review is not needed, or a link to one is included in the PR description
  • New files have MPL-2.0 license header
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

@github-actions github-actions bot added the CI/storybook-url Deploy storybook and provide a unique URL for each build label Oct 30, 2023
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@nullhook nullhook changed the title show privacy modal on input submit AIChat: Add Welcome guide Oct 31, 2023
@nullhook nullhook changed the title AIChat: Add Welcome guide AIChat: Add Welcome guide as a new opt-in UX Oct 31, 2023
@nullhook nullhook marked this pull request as ready for review October 31, 2023 23:29
Copy link
Contributor

The security team is monitoring all repositories for certain keywords. This PR includes the word(s) "policy" and so security team members have been added as reviewers to take a look.

No need to request a full security review at this stage, the security team will take a look shortly and either clear the label or request more information/changes.

Notifications have already been sent, but if this is blocking your merge feel free to reach out directly to the security team on Slack so that we can expedite this check.

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@nullhook nullhook requested a review from a team as a code owner November 1, 2023 06:14
@nullhook nullhook requested a review from petemill November 1, 2023 06:18
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

Copy link
Member

@petemill petemill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to handle pending messages in the c++, i.e. messages sent from the location bar pre opt-in. When fixing that, perhaps also put your pending clientside message their instead of making a new frontend state field for it.

@nullhook nullhook requested a review from petemill November 4, 2023 08:04
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@@ -316,7 +316,7 @@ void AIChatTabHelper::MaybeGeneratePageText() {
// Perf: make sure we're not doing this when the feature
// won't be used (e.g. not opted in or no active conversation).
if (is_page_text_fetch_in_progress_ || !article_text_.empty() ||
!HasUserOptedIn() || !is_conversation_active_ ||
!is_conversation_active_ ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You removed HasUserOptedIn and the comment doesn't make sense anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i will revise the comment

@@ -336,7 +336,8 @@ void AIChatTabHelper::MaybeGeneratePageText() {
FetchPageContent(
web_contents(),
base::BindOnce(&AIChatTabHelper::OnTabContentRetrieved,
weak_ptr_factory_.GetWeakPtr(), current_navigation_id_));
weak_ptr_factory_.GetWeakPtr(), current_navigation_id_),
HasUserOptedIn());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If HasUserOptedIn() is false then FetchPageContent doesn't do anything (if it has to make a fetch). So in those cases it won't get content. So why not avoid that complication by not calling FetchPageContent? As discussed, the opt-in UX doesn't need to know anything about the page content, it only needs to know if the page has content. At the moment all pages have content if they are http(s). Can't we just send that data to the page's opt-in UX so it can differ whether it shows the page content association or not? For example, SiteInfo can simply get an { isPresent: boolean } new property as well as title becoming optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user hasn't opted in, FetchPageContent will still be called. Previously, we would gate the call with various conditions, including the user not having opted in. However, now we send that boolean through. We gate it prior to sending results, and in the case of video, we don't make a network request.

@@ -20,7 +20,8 @@ function ConversationList() {
isGenerating,
conversationHistory,
suggestedQuestions,
shouldDisableUserInput
shouldDisableUserInput,
hasAcceptedAgreement
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldShowQuestions to avoid non-relevant logic in here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, what are you referring to here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have added a new prop to the ConverationList component: hasAcceptedAgreement. It means that the ConversationList component now needs to know what to show before or after the user has accepted the agreement. I'm suggesting it's better to keep all that logic in one place, at a higher level, than spread it around lower-level components. Hence, putting a prop such as shouldShowQuestions on this component instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, added

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@@ -149,4 +149,5 @@ interface ChatUIPage {
// |is_fetching| will be |true|.
OnSiteInfoChanged(bool is_fetching, SiteInfo? info);
OnFaviconImageDataChanged(array<uint8> favicon_image_data);
OnRequestPending();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too generic - how about it's named OnConversationEntryPending()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

Copy link
Collaborator

@mkarolin mkarolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings++

@nullhook
Copy link
Contributor Author

nullhook commented Nov 14, 2023

Thanks, I've addressed the UI issues you mentioned. However, there are minor font spacing and line-height differences. For example, the main title and subtitle have a 40px line height, but Figma uses 36px. Nala is currently undergoing upgrades, and it's taking some time due to the font hierarchy reconstruction.

Additionally, I've collaborated with @aguscruiz on graphic element positioning and font weights. He has made the necessary updates in Figma, so your screenshot may be outdated when reviewing this.

The dialog component has been replaced with Nala's as well.

@nullhook nullhook requested a review from petemill November 14, 2023 18:11
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

Comment on lines 92 to 102
// Trigger the observer because there might be a pending conversation entry.
// In some cases, this page handler hasn't been created and remote might not
// have been set yet, ensuring that we don't miss any UI updates, we trigger
// the observer again.
if (active_chat_tab_helper_ &&
active_chat_tab_helper_->HasPendingConversationEntry()) {
OnConversationEntryPending();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't really make sense to me - I think it's simply something like "Get current state data" - i.e. we're getting the current state because we haven't been around to get events yet. This is probably where we should put everything that's needed initially...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in essence, sure, it's getting "current state data" but that's obvious, right?

the not-so obvious part here is, why are we triggering OnConversationEntryPending event, specifically because no other events are there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have revised the comment which describes the scenario why this happens.

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@nullhook nullhook requested a review from petemill November 21, 2023 04:18
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@@ -159,7 +164,8 @@ class ConversationDriver {
mojom::APIError current_error_ = mojom::APIError::None;
mojom::PremiumStatus last_premium_status_ = mojom::PremiumStatus::Inactive;

std::unique_ptr<mojom::ConversationTurn> pending_request_;
std::unique_ptr<mojom::ConversationTurn> pending_conversation_entry_;
bool is_pending_content_retreival_ = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have bool is_page_text_fetch_in_progress_. How is this different? If there is reason to have both, then it would be clearer if they are next to each other and commented. I'm also wondering why ConversationDriver::HasPageContent doesn't need to consider this new property? Perhaps we should simplify by storing something like a PageContentAssociation page_status property.

@@ -102,7 +103,7 @@ function DataContextProvider (props: DataContextProviderProps) {
getPageHandlerInstance().pageHandler.generateQuestions()
}

const handleSiteInfo = (isFetching: boolean, siteInfo: mojom.SiteInfo | null) => {
const handleSiteInfo = (isFetching: boolean, siteInfo: mojom.SiteInfo | undefined) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem correct now that you've changed siteInfo to non-optional

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed: 87b88d3

void AIChatUIPageHandler::SubmitSummarizationRequestFromWelcomeView() {
mojom::ConversationTurn turn = {
CharacterType::HUMAN, ConversationTurnVisibility::VISIBLE,
l10n_util::GetStringUTF8(IDS_CHAT_UI_SUMMARIZE_PAGE)};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pretty fragile - we're using this specific string because we know that the ConversationDriver happens to treat it as a special summarization request. I think this decision should at least be contained within the same file. So, how about passing through SubmitSummarizationRequestFromWelcomeView to the ConversationDriver?

std::move(callback).Run(is_fetching_content, site_info.has_value()
? site_info.value().Clone()
: nullptr);
std::move(callback).Run(is_fetching_content, site_info.Clone());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be less confusing now that SiteInfo is non-optional, to put the fetching status as a property on SiteInfo, for GetSiteInfo and for OnSiteInfoChanged

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed: 87b88d3

site_info.is_content_truncated =
active_chat_tab_helper_->IsPageContentsTruncated();
site_info.is_content_present =
active_chat_tab_helper_->IsPageContentsPresent();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so confusing now - we have both ConversationDriver::HasPageContent and ConversationDriver::IsPageContentsPresent and it's not clear why they would differ. Can we use the existing HasPageContent? If we need it to do something else let's be explicit about the states that associated content can be in, e.g.

  • Fetching (i.e. "finding out")
  • Has Content
  • No Content
  • Other...?

I can see that IsPageContentsPresent is checking whether it can be present (based on the Url) and HasPageContent is checking whether we ended up getting content, but I think HasPageContent can change to do the check in IsPageContentsPresent.
We can also put the enum directly on SiteInfo if that's cleaner. Less to wonder about.

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@nullhook nullhook force-pushed the ai-chat-opt-in-ux branch 5 times, most recently from e120725 to 103342c Compare November 28, 2023 21:48
- dont send opt-in bool
- siteinfo has a new prop
- rename pending conversation entries
- uses nala dialog
- nala dialog width should work
- flush welcome guide to bottom
- introducing should_show_questions prop
- added pending_message_needs_page_content_
- siteInfo is non-optional
- added logic to show_suggestion bool
- special summarization request
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@nullhook
Copy link
Contributor Author

closing this in-lieu of: #20966

@nullhook nullhook closed this Nov 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI/storybook-url Deploy storybook and provide a unique URL for each build
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AI Chat: Update opt-in experience
6 participants