FEATURE: remember previously selected persona (#299)

People tend to keep to 1 persona when working with the bot,
this adds local browser memory for the last persona you interacted
with so you do not need to select it over and over again.

This is per browser, not per user memory.

Also... clean up tests so they do not need to require stubs which
were breaking the build

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
This commit is contained in:
Sam 2023-11-21 18:02:27 +11:00 committed by GitHub
parent 5b5edb22c6
commit 98c89953d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 36 additions and 15 deletions

View File

@ -1,6 +1,7 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { hash } from "@ember/helper"; import { hash } from "@ember/helper";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import KeyValueStore from "discourse/lib/key-value-store";
import DropdownSelectBox from "select-kit/components/dropdown-select-box"; import DropdownSelectBox from "select-kit/components/dropdown-select-box";
function isBotMessage(composer, currentUser) { function isBotMessage(composer, currentUser) {
@ -27,10 +28,21 @@ export default class BotSelector extends Component {
} }
@service currentUser; @service currentUser;
STORE_NAMESPACE = "discourse_ai_persona_selector_";
preferredPersonaStore = new KeyValueStore(this.STORE_NAMESPACE);
constructor() { constructor() {
super(...arguments); super(...arguments);
if (this.botOptions && this.composer) { if (this.botOptions && this.composer) {
this._value = this.botOptions[0].id; const personaId = this.preferredPersonaStore.getObject("id");
if (personaId) {
this._value = parseInt(personaId, 10);
} else {
this._value = this.botOptions[0].personaId;
}
this.composer.metaData = { ai_persona_id: this._value }; this.composer.metaData = { ai_persona_id: this._value };
} }
} }
@ -55,14 +67,16 @@ export default class BotSelector extends Component {
return this._value; return this._value;
} }
set value(val) { set value(newValue) {
this._value = val; this._value = newValue;
this.composer.metaData = { ai_persona_id: val }; this.preferredPersonaStore.setObject({ key: "id", value: newValue });
this.composer.metaData = { ai_persona_id: newValue };
} }
<template> <template>
<div class="gpt-persona"> <div class="gpt-persona">
<DropdownSelectBox <DropdownSelectBox
class="persona-selector__dropdown"
@value={{this.value}} @value={{this.value}}
@content={{this.botOptions}} @content={{this.botOptions}}
@options={{hash icon="robot"}} @options={{hash icon="robot"}}

View File

@ -88,5 +88,6 @@ after_initialize do
require_relative "spec/support/openai_completions_inference_stubs" require_relative "spec/support/openai_completions_inference_stubs"
require_relative "spec/support/anthropic_completion_stubs" require_relative "spec/support/anthropic_completion_stubs"
require_relative "spec/support/stable_diffusion_stubs" require_relative "spec/support/stable_diffusion_stubs"
require_relative "spec/support/embeddings_generation_stubs"
end end
end end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../../../support/embeddings_generation_stubs"
RSpec.describe Jobs::GenerateEmbeddings do RSpec.describe Jobs::GenerateEmbeddings do
subject(:job) { described_class.new } subject(:job) { described_class.new }

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../../support/embeddings_generation_stubs"
RSpec.describe DiscourseAi::Embeddings::SemanticSearch do RSpec.describe DiscourseAi::Embeddings::SemanticSearch do
fab!(:post) { Fabricate(:post) } fab!(:post) { Fabricate(:post) }
fab!(:user) { Fabricate(:user) } fab!(:user) { Fabricate(:user) }

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../../../support/embeddings_generation_stubs"
require_relative "vector_rep_shared_examples" require_relative "vector_rep_shared_examples"
RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::AllMpnetBaseV2 do RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::AllMpnetBaseV2 do

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../../../support/embeddings_generation_stubs"
require_relative "vector_rep_shared_examples" require_relative "vector_rep_shared_examples"
RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::MultilingualE5Large do RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::MultilingualE5Large do

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../../../support/embeddings_generation_stubs"
require_relative "vector_rep_shared_examples" require_relative "vector_rep_shared_examples"
RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::TextEmbeddingAda002 do RSpec.describe DiscourseAi::Embeddings::VectorRepresentations::TextEmbeddingAda002 do

View File

@ -4,8 +4,24 @@ RSpec.describe "AI personas", type: :system, js: true do
before do before do
SiteSetting.ai_bot_enabled = true SiteSetting.ai_bot_enabled = true
SiteSetting.ai_bot_enabled_chat_bots = "gpt-4|gpt-3.5-turbo" SiteSetting.ai_bot_enabled_chat_bots = "gpt-4"
sign_in(admin) sign_in(admin)
Group.refresh_automatic_groups!
end
it "remembers the last selected persona" do
visit "/"
find(".d-header .ai-bot-button").click()
persona_selector = PageObjects::Components::SelectKit.new(".persona-selector__dropdown")
persona_selector.expand
persona_selector.select_row_by_value(-2)
visit "/"
find(".d-header .ai-bot-button").click()
persona_selector = PageObjects::Components::SelectKit.new(".persona-selector__dropdown")
persona_selector.expand
expect(persona_selector).to have_selected_value(-2)
end end
it "allows creation of a persona" do it "allows creation of a persona" do

View File

@ -1,8 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../support/embeddings_generation_stubs"
require_relative "../../support/openai_completions_inference_stubs"
RSpec.describe "AI Composer helper", type: :system, js: true do RSpec.describe "AI Composer helper", type: :system, js: true do
let(:search_page) { PageObjects::Pages::Search.new } let(:search_page) { PageObjects::Pages::Search.new }
let(:query) { "apple_pie" } let(:query) { "apple_pie" }