FEATURE: Continue conversation from Discobot discovery (#1234)
This feature update allows for continuing the conversation with Discobot Discoveries in an AI bot chat. After discoveries gives you a response to your search you can continue with the existing context.
This commit is contained in:
parent
5331b6dd8e
commit
bf5ccb452c
|
@ -69,6 +69,40 @@ module DiscourseAi
|
|||
|
||||
render json: {}, status: 200
|
||||
end
|
||||
|
||||
def discover_continue_convo
|
||||
raise Discourse::InvalidParameters.new("user_id") if !params[:user_id]
|
||||
raise Discourse::InvalidParameters.new("query") if !params[:query]
|
||||
raise Discourse::InvalidParameters.new("context") if !params[:context]
|
||||
|
||||
user = User.find(params[:user_id])
|
||||
|
||||
bot_user_id = AiPersona.find_by(id: SiteSetting.ai_bot_discover_persona).user_id
|
||||
bot_username = User.find_by(id: bot_user_id).username
|
||||
|
||||
query = params[:query]
|
||||
context = "[quote]\n#{params[:context]}\n[/quote]"
|
||||
|
||||
post =
|
||||
PostCreator.create!(
|
||||
user,
|
||||
title:
|
||||
I18n.t("discourse_ai.ai_bot.discoveries.continue_conversation.title", query: query),
|
||||
raw:
|
||||
I18n.t(
|
||||
"discourse_ai.ai_bot.discoveries.continue_conversation.raw",
|
||||
query: query,
|
||||
context: context,
|
||||
),
|
||||
archetype: Archetype.private_message,
|
||||
target_usernames: bot_username,
|
||||
skip_validations: true,
|
||||
)
|
||||
|
||||
render json: success_json.merge(topic_id: post.topic_id)
|
||||
rescue StandardError => e
|
||||
render json: failed_json.merge(errors: [e.message]), status: 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,11 +10,15 @@ import CookText from "discourse/components/cook-text";
|
|||
import DButton from "discourse/components/d-button";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import Topic from "discourse/models/topic";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import SmoothStreamer from "../lib/smooth-streamer";
|
||||
import AiBlinkingAnimation from "./ai-blinking-animation";
|
||||
import AiIndicatorWave from "./ai-indicator-wave";
|
||||
|
||||
const DISCOVERY_TIMEOUT_MS = 10000;
|
||||
|
||||
|
@ -23,7 +27,11 @@ export default class AiSearchDiscoveries extends Component {
|
|||
@service messageBus;
|
||||
@service discobotDiscoveries;
|
||||
@service appEvents;
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
@service composer;
|
||||
|
||||
@tracked loadingConversationTopic = false;
|
||||
@tracked hideDiscoveries = false;
|
||||
@tracked fullDiscoveryToggled = false;
|
||||
@tracked discoveryPreviewLength = this.args.discoveryPreviewLength || 150;
|
||||
|
@ -145,6 +153,28 @@ export default class AiSearchDiscoveries extends Component {
|
|||
return !this.fullDiscoveryToggled && this.canShowExpandtoggle;
|
||||
}
|
||||
|
||||
get canContinueConversation() {
|
||||
const personas = this.currentUser?.ai_enabled_personas;
|
||||
const discoverPersona = personas.find(
|
||||
(persona) => persona.id === this.siteSettings?.ai_bot_discover_persona
|
||||
);
|
||||
const discoverPersonaHasBot = discoverPersona?.username;
|
||||
|
||||
return (
|
||||
this.discobotDiscoveries.discovery?.length > 0 &&
|
||||
!this.smoothStreamer.isStreaming &&
|
||||
discoverPersonaHasBot
|
||||
);
|
||||
}
|
||||
|
||||
get continueConvoBtnLabel() {
|
||||
if (this.loadingConversationTopic) {
|
||||
return "discourse_ai.discobot_discoveries.loading_convo";
|
||||
}
|
||||
|
||||
return "discourse_ai.discobot_discoveries.continue_convo";
|
||||
}
|
||||
|
||||
@action
|
||||
async triggerDiscovery() {
|
||||
if (this.discobotDiscoveries.lastQuery === this.query) {
|
||||
|
@ -180,6 +210,43 @@ export default class AiSearchDiscoveries extends Component {
|
|||
this.fullDiscoveryToggled = !this.fullDiscoveryToggled;
|
||||
}
|
||||
|
||||
@action
|
||||
async continueConversation() {
|
||||
const data = {
|
||||
user_id: this.currentUser.id,
|
||||
query: this.query,
|
||||
context: this.discobotDiscoveries.discovery,
|
||||
};
|
||||
try {
|
||||
this.loadingConversationTopic = true;
|
||||
const continueRequest = await ajax(
|
||||
`/discourse-ai/ai-bot/discover/continue-convo`,
|
||||
{
|
||||
type: "POST",
|
||||
data,
|
||||
}
|
||||
);
|
||||
const topicJSON = await Topic.find(continueRequest.topic_id, {});
|
||||
const topic = Topic.create(topicJSON);
|
||||
|
||||
DiscourseURL.routeTo(`/t/${continueRequest.topic_id}`, {
|
||||
afterRouteComplete: () => {
|
||||
if (this.args.closeSearchMenu) {
|
||||
this.args.closeSearchMenu();
|
||||
}
|
||||
|
||||
this.composer.focusComposer({
|
||||
topic,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
popupAjaxError(e);
|
||||
} finally {
|
||||
this.loadingConversationTopic = false;
|
||||
}
|
||||
}
|
||||
|
||||
timeoutDiscovery() {
|
||||
this.discobotDiscoveries.loadingDiscoveries = false;
|
||||
this.discobotDiscoveries.discovery = "";
|
||||
|
@ -226,6 +293,18 @@ export default class AiSearchDiscoveries extends Component {
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.canContinueConversation}}
|
||||
<div class="ai-search-discoveries__continue-conversation">
|
||||
<DButton
|
||||
@action={{this.continueConversation}}
|
||||
@label={{this.continueConvoBtnLabel}}
|
||||
class="btn-small"
|
||||
>
|
||||
<AiIndicatorWave @loading={{this.loadingConversationTopic}} />
|
||||
</DButton>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export default class AiDiscobotDiscoveries extends Component {
|
|||
<AiSearchDiscoveries
|
||||
@searchTerm={{@outletArgs.searchTerm}}
|
||||
@discoveryPreviewLength={{50}}
|
||||
@closeSearchMenu={{@outletArgs.closeSearchMenu}}
|
||||
/>
|
||||
|
||||
{{#if this.search.results.topics.length}}
|
||||
|
|
|
@ -62,6 +62,10 @@
|
|||
.cooked p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&__continue-conversation {
|
||||
margin-block: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ai-search-discoveries-tooltip {
|
||||
|
|
|
@ -731,6 +731,8 @@ en:
|
|||
main_title: "Discobot discoveries"
|
||||
regular_results: "Topics"
|
||||
tell_me_more: "Tell me more..."
|
||||
continue_convo: "Continue conversation..."
|
||||
loading_convo: "Loading conversation"
|
||||
collapse: "Collapse"
|
||||
timed_out: "Discobot couldn't find any discoveries. Something went wrong."
|
||||
user_setting: "Enable search discoveries"
|
||||
|
|
|
@ -422,6 +422,10 @@ en:
|
|||
search_settings:
|
||||
one: "Found %{count} result for '%{query}'"
|
||||
other: "Found %{count} results for '%{query}'"
|
||||
discoveries:
|
||||
continue_conversation:
|
||||
title: "Discovery conversation: Search for %{query}"
|
||||
raw: "In my search for %{query}, you showed me the following information:\n\n%{context}\n\nLet's continue the conversation."
|
||||
|
||||
summarization:
|
||||
configuration_hint:
|
||||
|
|
|
@ -26,6 +26,7 @@ DiscourseAi::Engine.routes.draw do
|
|||
post "post/:post_id/stop-streaming" => "bot#stop_streaming_response"
|
||||
|
||||
get "discover" => "bot#discover"
|
||||
post "discover/continue-convo" => "bot#discover_continue_convo"
|
||||
end
|
||||
|
||||
scope module: :ai_bot, path: "/ai-bot/shared-ai-conversations" do
|
||||
|
|
|
@ -168,4 +168,71 @@ RSpec.describe DiscourseAi::AiBot::BotController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#discover_continue_convo" do
|
||||
before { SiteSetting.ai_bot_enabled = true }
|
||||
fab!(:group)
|
||||
fab!(:llm_model)
|
||||
fab!(:ai_persona) do
|
||||
persona = Fabricate(:ai_persona, allowed_group_ids: [group.id], default_llm_id: llm_model.id)
|
||||
persona.create_user!
|
||||
persona
|
||||
end
|
||||
let(:query) { "What is Discourse?" }
|
||||
let(:context) { "Discourse is an open-source discussion platform." }
|
||||
|
||||
context "when the user is allowed to discover" do
|
||||
before do
|
||||
SiteSetting.ai_bot_discover_persona = ai_persona.id
|
||||
group.add(user)
|
||||
end
|
||||
|
||||
it "returns a 200 and creates a private message topic" do
|
||||
expect {
|
||||
post "/discourse-ai/ai-bot/discover/continue-convo",
|
||||
params: {
|
||||
user_id: user.id,
|
||||
query: query,
|
||||
context: context,
|
||||
}
|
||||
}.to change(Topic, :count).by(1)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_id"]).to be_present
|
||||
end
|
||||
|
||||
it "returns invalid parameters if the user_id is missing" do
|
||||
post "/discourse-ai/ai-bot/discover/continue-convo",
|
||||
params: {
|
||||
query: query,
|
||||
context: context,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(422)
|
||||
expect(response.parsed_body["errors"]).to include("user_id")
|
||||
end
|
||||
|
||||
it "returns invalid parameters if the query is missing" do
|
||||
post "/discourse-ai/ai-bot/discover/continue-convo",
|
||||
params: {
|
||||
user_id: user.id,
|
||||
context: context,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(422)
|
||||
expect(response.parsed_body["errors"]).to include("query")
|
||||
end
|
||||
|
||||
it "returns invalid parameters if the context is missing" do
|
||||
post "/discourse-ai/ai-bot/discover/continue-convo",
|
||||
params: {
|
||||
user_id: user.id,
|
||||
query: query,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(422)
|
||||
expect(response.parsed_body["errors"]).to include("context")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue