FIX: Search discoveries improvements (#1228)

**This update makes a few improvements to search discoveries:**
- [x] in search menu panel: search discoveries should still be triggered when no regular results are present
- [x] in full page search: search discoveries should still be triggered when no regular results are present
- [x] flakiness in search discoveries sometimes not working properly.

---------

Co-authored-by: awesomerobot <kris.aubuchon@discourse.org>
This commit is contained in:
Keegan George 2025-03-31 08:38:40 -07:00 committed by GitHub
parent 28fa723472
commit f3e78f0d80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 94 additions and 44 deletions

View File

@ -11,6 +11,7 @@ import DButton from "discourse/components/d-button";
import concatClass from "discourse/helpers/concat-class";
import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse/lib/decorators";
import { withPluginApi } from "discourse/lib/plugin-api";
import { i18n } from "discourse-i18n";
import SmoothStreamer from "../lib/smooth-streamer";
import AiBlinkingAnimation from "./ai-blinking-animation";
@ -23,7 +24,6 @@ export default class AiSearchDiscoveries extends Component {
@service discobotDiscoveries;
@service appEvents;
@tracked loadingDiscoveries = false;
@tracked hideDiscoveries = false;
@tracked fullDiscoveryToggled = false;
@tracked discoveryPreviewLength = this.args.discoveryPreviewLength || 150;
@ -34,8 +34,6 @@ export default class AiSearchDiscoveries extends Component {
);
discoveryTimeout = null;
typingTimer = null;
streamedTextLength = 0;
constructor() {
super(...arguments);
@ -55,6 +53,34 @@ export default class AiSearchDiscoveries extends Component {
);
}
@bind
detectSearch() {
if (
this.query?.length === 0 &&
this.discobotDiscoveries.discovery?.length > 0
) {
this.discobotDiscoveries.resetDiscovery();
this.smoothStreamer.resetStreaming();
}
withPluginApi((api) => {
api.addSearchMenuOnKeyDownCallback((searchMenu, event) => {
if (!searchMenu || this.discobotDiscoveries.loadingDiscoveries) {
return;
}
if (this.discobotDiscoveries.lastQuery === this.query) {
return false;
}
if (event.key === "Enter" && this.query) {
this.triggerDiscovery();
}
return true;
});
});
}
@bind
async _updateDiscovery(update) {
if (this.query === update.query) {
@ -67,7 +93,7 @@ export default class AiSearchDiscoveries extends Component {
}
this.discobotDiscoveries.modelUsed = update.model_used;
this.loadingDiscoveries = false;
this.discobotDiscoveries.loadingDiscoveries = false;
this.smoothStreamer.updateResult(update, "ai_discover_reply");
}
}
@ -110,7 +136,7 @@ export default class AiSearchDiscoveries extends Component {
get canShowExpandtoggle() {
return (
!this.loadingDiscoveries &&
!this.discobotDiscoveries.loadingDiscoveries &&
this.smoothStreamer.renderedText.length > this.discoveryPreviewLength
);
}
@ -130,7 +156,8 @@ export default class AiSearchDiscoveries extends Component {
}
this.hideDiscoveries = false;
this.loadingDiscoveries = true;
this.discobotDiscoveries.loadingDiscoveries = true;
this.discoveryTimeout = later(
this,
this.timeoutDiscovery,
@ -139,6 +166,7 @@ export default class AiSearchDiscoveries extends Component {
try {
this.discobotDiscoveries.lastQuery = this.query;
await ajax("/discourse-ai/ai-bot/discover", {
data: { query: this.query },
});
@ -153,7 +181,7 @@ export default class AiSearchDiscoveries extends Component {
}
timeoutDiscovery() {
this.loadingDiscoveries = false;
this.discobotDiscoveries.loadingDiscoveries = false;
this.discobotDiscoveries.discovery = "";
this.discobotDiscoveries.discoveryTimedOut = true;
@ -162,13 +190,14 @@ export default class AiSearchDiscoveries extends Component {
<template>
<div
class="ai-search-discoveries"
{{didInsert this.subscribe @searchTerm}}
{{didUpdate this.subscribe @searchTerm}}
{{didInsert this.subscribe this.query}}
{{didUpdate this.subscribe this.query}}
{{didUpdate this.detectSearch this.query}}
{{didInsert this.triggerDiscovery this.query}}
{{willDestroy this.unsubscribe}}
>
<div class="ai-search-discoveries__completion">
{{#if this.loadingDiscoveries}}
{{#if this.discobotDiscoveries.loadingDiscoveries}}
<AiBlinkingAnimation />
{{else if this.discobotDiscoveries.discoveryTimedOut}}
{{i18n "discourse_ai.discobot_discoveries.timed_out"}}
@ -181,9 +210,10 @@ export default class AiSearchDiscoveries extends Component {
"streamable-content"
}}
>
<div class="cooked">
<CookText @rawText={{this.smoothStreamer.renderedText}} />
</div>
<CookText
@rawText={{this.smoothStreamer.renderedText}}
class="cooked"
/>
</article>
{{#if this.canShowExpandtoggle}}

View File

@ -16,12 +16,8 @@ export default class AiFullPageDiscobotDiscoveries extends Component {
@service discobotDiscoveries;
get hasDiscoveries() {
return this.args.outletArgs?.model?.topics?.length > 0;
}
<template>
{{#if this.hasDiscoveries}}
{{#if this.discobotDiscoveries.showDiscoveryTitle}}
<h3
class="ai-search-discoveries__discoveries-title full-page-discoveries"
>
@ -32,9 +28,10 @@ export default class AiFullPageDiscobotDiscoveries extends Component {
<AiSearchDiscoveriesTooltip />
</h3>
<div class="full-page-discoveries">
<AiSearchDiscoveries @searchTerm={{@outletArgs.search}} />
</div>
{{/if}}
<div class="full-page-discoveries">
<AiSearchDiscoveries @searchTerm={{@outletArgs.search}} />
</div>
</template>
}

View File

@ -8,7 +8,6 @@ import AiSearchDiscoveriesTooltip from "../../components/ai-search-discoveries-t
export default class AiDiscobotDiscoveries extends Component {
static shouldRender(args, { siteSettings, currentUser }) {
return (
args.resultType.type === "topic" &&
siteSettings.ai_bot_discover_persona &&
currentUser?.can_use_ai_bot_discover_persona &&
currentUser?.user_option?.ai_search_discoveries
@ -16,24 +15,32 @@ export default class AiDiscobotDiscoveries extends Component {
}
@service discobotDiscoveries;
@service search;
<template>
<div class="ai-discobot-discoveries">
<h3 class="ai-search-discoveries__discoveries-title">
<span>
{{icon "discobot"}}
{{i18n "discourse_ai.discobot_discoveries.main_title"}}
</span>
{{#if this.discobotDiscoveries.showDiscoveryTitle}}
<h3 class="ai-search-discoveries__discoveries-title">
<span>
{{icon "discobot"}}
{{i18n "discourse_ai.discobot_discoveries.main_title"}}
</span>
<AiSearchDiscoveriesTooltip />
</h3>
<AiSearchDiscoveriesTooltip />
</h3>
{{/if}}
<AiSearchDiscoveries @discoveryPreviewLength={{50}} />
<AiSearchDiscoveries
@searchTerm={{@outletArgs.searchTerm}}
@discoveryPreviewLength={{50}}
/>
<h3 class="ai-search-discoveries__regular-results-title">
{{icon "bars-staggered"}}
{{i18n "discourse_ai.discobot_discoveries.regular_results"}}
</h3>
{{#if this.search.results.topics.length}}
<h3 class="ai-search-discoveries__regular-results-title">
{{icon "bars-staggered"}}
{{i18n "discourse_ai.discobot_discoveries.regular_results"}}
</h3>
{{/if}}
</div>
</template>
}

View File

@ -11,13 +11,19 @@ export default class DiscobotDiscoveries extends Service {
@tracked lastQuery = "";
@tracked discoveryTimedOut = false;
@tracked modelUsed = "";
@tracked loadingDiscoveries = false;
resetDiscovery() {
this.loadingDiscoveries = false;
this.discovery = "";
this.discoveryTimedOut = false;
this.modelUsed = "";
}
get showDiscoveryTitle() {
return this.discovery.length > 0 || this.loadingDiscoveries;
}
@action
async disableDiscoveries() {
this.currentUser.user_option.ai_search_discoveries = false;

View File

@ -10,6 +10,7 @@
.ai-search-discoveries {
&__regular-results-title {
margin-top: 0.5em;
margin-bottom: 0;
}
@ -93,10 +94,6 @@
}
}
.ai-discobot-discoveries {
padding: 0.5em;
}
.full-page-discoveries {
padding: 1em 10%;
}
@ -107,30 +104,43 @@
width: 1.15em;
}
.ai-discobot-discoveries {
padding-top: 0.5em;
}
@include breakpoint("medium", min-width) {
.search-menu .menu-panel:has(.ai-discobot-discoveries) {
.search-menu .menu-panel:has(.ai-search-discoveries__discoveries-title) {
width: 80vw;
max-width: 800px;
transition: width 0.5s;
.search-result-topic {
.results {
display: grid;
grid-template-areas: "results-title ai-title" "results ai";
grid-template-columns: 58% 38%;
grid-template-rows: auto auto 1fr;
gap: 0 4%;
.list {
grid-area: results;
* {
// covers all non-discovery content
grid-column-start: 1;
}
.ai-discobot-discoveries {
grid-area: ai;
// always in the second column, always spans all rows
grid-column-start: 2;
grid-row: 1 / -1;
padding-top: 0;
}
}
.ai-search-discoveries {
font-size: var(--font-0);
color: var(--primary-high);
padding-right: 0.5em;
}
.ai-search-discoveries__discoveries-title {
margin-top: 0.5em;
}
.ai-search-discoveries__regular-results-title {