Skip to content

Commit

Permalink
UX: improve embeddings config styles (#1085)
Browse files Browse the repository at this point in the history
* WIP: improve embeddings config styles

* switch to textarea, fix back button

* remove log, update button, fix tests

* stree

* fix spec

* spec fix

* remove comment
  • Loading branch information
awesomerobot authored Jan 24, 2025
1 parent 952e0a5 commit 99e73f0
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 50 deletions.
6 changes: 3 additions & 3 deletions app/models/embedding_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def presets
# indexes, so we downsample to 2000 via API.
{
preset_id: "text-embedding-3-large",
display_name: "OpenAI's text-embedding-3-large",
display_name: "text-embedding-3-large",
dimensions: 2000,
max_sequence_length: 8191,
pg_function: "<=>",
Expand All @@ -91,7 +91,7 @@ def presets
},
{
preset_id: "text-embedding-3-small",
display_name: "OpenAI's text-embedding-3-small",
display_name: "text-embedding-3-small",
dimensions: 1536,
max_sequence_length: 8191,
pg_function: "<=>",
Expand All @@ -105,7 +105,7 @@ def presets
},
{
preset_id: "text-embedding-ada-002",
display_name: "OpenAI's text-embedding-ada-002",
display_name: "text-embedding-ada-002",
dimensions: 1536,
max_sequence_length: 8191,
pg_function: "<=>",
Expand Down
124 changes: 94 additions & 30 deletions assets/javascripts/discourse/components/ai-embedding-editor.gjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { Input } from "@ember/component";
import { concat, get } from "@ember/helper";
import { Input, Textarea } from "@ember/component";
import { concat, fn, get } from "@ember/helper";
import { on } from "@ember/modifier";
import { action, computed } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
Expand All @@ -13,6 +13,8 @@ import DButton from "discourse/components/d-button";
import icon from "discourse/helpers/d-icon";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { i18n } from "discourse-i18n";
import AdminSectionLandingItem from "admin/components/admin-section-landing-item";
import AdminSectionLandingWrapper from "admin/components/admin-section-landing-wrapper";
import ComboBox from "select-kit/components/combo-box";
import DTooltip from "float-kit/components/d-tooltip";
import not from "truth-helpers/helpers/not";
Expand Down Expand Up @@ -48,7 +50,19 @@ export default class AiEmbeddingEditor extends Component {
};

return this.args.embeddings.resultSetMeta.distance_functions.map((df) => {
return { id: df, name: t(df) };
let iconName;

if (df === "<=>") {
iconName = "discourse-spaceship-operator";
} else if (df === "<#>") {
iconName = "discourse-negative-inner-product";
}

return {
id: df,
name: t(df),
icon: iconName,
};
});
}

Expand All @@ -57,12 +71,14 @@ export default class AiEmbeddingEditor extends Component {
return {
name: preset.display_name,
id: preset.preset_id,
provider: preset.provider,
};
});

presets.pushObject({
presets.unshiftObject({
name: i18n("discourse_ai.embeddings.configure_manually"),
id: "manual",
provider: "fake",
});

return presets;
Expand Down Expand Up @@ -90,11 +106,11 @@ export default class AiEmbeddingEditor extends Component {
}

@action
configurePreset() {
configurePreset(preset) {
this.selectedPreset =
this.args.embeddings.resultSetMeta.presets.findBy(
"preset_id",
this.presetId
preset.id
) || {};

this.editingModel = this.store
Expand Down Expand Up @@ -185,35 +201,64 @@ export default class AiEmbeddingEditor extends Component {
});
}

<template>
<BackButton
@route="adminPlugins.show.discourse-ai-embeddings"
@label="discourse_ai.embeddings.back"
/>
@action
resetForm() {
this.selectedPreset = null;
this.editingModel = null;
}

<template>
<form
{{didInsert this.updateModel @model.id}}
{{didUpdate this.updateModel @model.id}}
class="form-horizontal ai-embedding-editor"
>
{{#if this.showPresets}}
<BackButton
@route="adminPlugins.show.discourse-ai-embeddings"
@label="discourse_ai.embeddings.back"
/>
<div class="control-group">
<label>{{i18n "discourse_ai.embeddings.presets"}}</label>
<ComboBox
@value={{this.presetId}}
@content={{this.presets}}
class="ai-embedding-editor__presets"
/>
<h2>{{i18n "discourse_ai.embeddings.presets"}}</h2>
<AdminSectionLandingWrapper>
{{#each this.presets as |preset|}}
<AdminSectionLandingItem
@titleLabelTranslated={{preset.name}}
@taglineLabel={{concat
"discourse_ai.embeddings.providers."
preset.provider
}}
data-preset-id={{preset.id}}
class="ai-llms-list-editor__templates-list-item"
>
<:buttons as |buttons|>
<buttons.Default
@action={{fn this.configurePreset preset}}
@icon="gear"
@label="discourse_ai.llms.preconfigured.button"
/>
</:buttons>
</AdminSectionLandingItem>

{{/each}}
</AdminSectionLandingWrapper>

</div>

<div class="control-group ai-llm-editor__action_panel">
{{else}}
{{#if this.editingModel.isNew}}
<DButton
@action={{this.configurePreset}}
@label="discourse_ai.tools.next.title"
class="ai-embedding-editor__next"
@action={{this.resetForm}}
@label="back_button"
@icon="chevron-left"
class="btn-flat back-button"
/>
</div>
{{else}}
{{else}}
<BackButton
@route="adminPlugins.show.discourse-ai-embeddings"
@label="discourse_ai.embeddings.back"
/>
{{/if}}
<div class="control-group">
<label>{{i18n "discourse_ai.embeddings.display_name"}}</label>
<Input
Expand Down Expand Up @@ -295,27 +340,38 @@ export default class AiEmbeddingEditor extends Component {
@type="checkbox"
@checked={{this.editingModel.matryoshka_dimensions}}
/>
<label>{{i18n
"discourse_ai.embeddings.matryoshka_dimensions"
}}</label>
<label>{{i18n "discourse_ai.embeddings.matryoshka_dimensions"}}
</label>
<DTooltip
@icon="circle-question"
@content={{i18n
"discourse_ai.embeddings.hints.matryoshka_dimensions"
}}
/>
</div>

<div class="control-group">
<label>{{i18n "discourse_ai.embeddings.embed_prompt"}}</label>
<Input
@type="text"
<Textarea
class="ai-embedding-editor-input ai-embedding-editor__embed_prompt"
@value={{this.editingModel.embed_prompt}}
/>
<DTooltip
@icon="circle-question"
@content={{i18n "discourse_ai.embeddings.hints.embed_prompt"}}
/>
</div>

<div class="control-group">
<label>{{i18n "discourse_ai.embeddings.search_prompt"}}</label>
<Input
@type="text"
<Textarea
class="ai-embedding-editor-input ai-embedding-editor__search_prompt"
@value={{this.editingModel.search_prompt}}
/>
<DTooltip
@icon="circle-question"
@content={{i18n "discourse_ai.embeddings.hints.search_prompt"}}
/>
</div>

<div class="control-group">
Expand All @@ -329,6 +385,10 @@ export default class AiEmbeddingEditor extends Component {
@value={{this.editingModel.max_sequence_length}}
required="true"
/>
<DTooltip
@icon="circle-question"
@content={{i18n "discourse_ai.embeddings.hints.sequence_length"}}
/>
</div>

<div class="control-group">
Expand All @@ -338,6 +398,10 @@ export default class AiEmbeddingEditor extends Component {
@content={{this.distanceFunctions}}
@class="ai-embedding-editor__distance_functions"
/>
<DTooltip
@icon="circle-question"
@content={{i18n "discourse_ai.embeddings.hints.distance_function"}}
/>
</div>

{{#each-in this.metaProviderParams as |field type|}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,47 @@
display: flex;
align-items: flex-start;
}

&__distance_functions.select-kit {
.selected-name {
.d-icon {
width: 2em;
height: 2em;
position: absolute;

+ .name {
margin-left: 2.25em;
}
}
}

.svg-icon-title {
width: 2em;
top: -0.5em;

svg {
width: 2em;
height: 2em;
}
}
}
}

.discourse-ai-embeddings {
.btn-flat.back-button {
padding-left: 0;
}

.fk-d-tooltip__icon {
margin-left: 0.25em;
color: var(--primary-medium);
}

textarea + .fk-d-tooltip__trigger {
vertical-align: top;
}

.d-icon-circle-exclamation {
color: var(--danger);
}
}
14 changes: 9 additions & 5 deletions config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,18 @@ en:
configure_manually: "Configure manually"
edit: "Edit"
seeded_warning: "This is pre-configured on your site and cannot be edited."
tests:
tests:
title: "Run test"
running: "Running test..."
success: "Success!"
failure: "Attempting to generate an embedding resulted in: %{error}"
hints:
dimensions_warning: "Once saved, this value can't be changed."

matryoshka_dimensions: "Defines the size of nested embeddings used for hierarchical or multi-layered representation of data, similar to how nested dolls fit within each other."
embed_prompt: "Tells the LLM how to process text to create its numerical summary (embedding) for analysis or comparison."
search_prompt: "Tells the LLM how to compare a search query with existing embeddings and find the best matches."
sequence_length: "The maximum number of tokens that can be processed at once when creating embeddings or handling a query."
distance_function: "Determines how similarity between embeddings is calculated, using either cosine distance (measuring the angle between vectors) or negative inner product (measuring overlap of vector values)."
display_name: "Name"
provider: "Provider"
url: "Embeddings service URL"
Expand All @@ -536,18 +540,18 @@ en:

distance_function: "Distance function"
distance_functions:
<#>: "Negative inner product (<#>)"
<=>: "Cosine distance (<=>)"
<#>: "Negative inner product"
<=>: "Cosine distance"
providers:
hugging_face: "Hugging Face"
open_ai: "OpenAI"
google: "Google"
cloudflare: "Cloudflare"
CDCK: "CDCK"
fake: "Custom"
provider_fields:
model_name: "Model name"


semantic_search: "Topics (Semantic)"
semantic_search_loading: "Searching for more results using AI"
semantic_search_results:
Expand Down
19 changes: 8 additions & 11 deletions spec/system/embeddings/ai_embedding_definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
visit "/admin/plugins/discourse-ai/ai-embeddings"

find(".ai-embeddings-list-editor__new-button").click()
select_kit = PageObjects::Components::SelectKit.new(".ai-embedding-editor__presets")
select_kit.expand
select_kit.select_row_by_value(preset)
find(".ai-embedding-editor__next").click

find("[data-preset-id='text-embedding-3-small'] button").click()

find("input.ai-embedding-editor__api-key").fill_in(with: api_key)
find(".ai-embedding-editor__save").click()

Expand All @@ -43,12 +42,10 @@
visit "/admin/plugins/discourse-ai/ai-embeddings"

find(".ai-embeddings-list-editor__new-button").click()
select_kit = PageObjects::Components::SelectKit.new(".ai-embedding-editor__presets")
select_kit.expand
select_kit.select_row_by_value("manual")
find(".ai-embedding-editor__next").click

find("input.ai-embedding-editor__display-name").fill_in(with: "OpenAI's text-embedding-3-small")
find("[data-preset-id='manual'] button").click()

find("input.ai-embedding-editor__display-name").fill_in(with: "text-embedding-3-small")

select_kit = PageObjects::Components::SelectKit.new(".ai-embedding-editor__provider")
select_kit.expand
Expand All @@ -63,8 +60,8 @@

embed_prefix = "On creation:"
search_prefix = "On search:"
find("input.ai-embedding-editor__embed_prompt").fill_in(with: embed_prefix)
find("input.ai-embedding-editor__search_prompt").fill_in(with: search_prefix)
find(".ai-embedding-editor__embed_prompt").fill_in(with: embed_prefix)
find(".ai-embedding-editor__search_prompt").fill_in(with: search_prefix)

find("input.ai-embedding-editor__dimensions").fill_in(with: 1536)
find("input.ai-embedding-editor__max_sequence_length").fill_in(with: 8191)
Expand Down
12 changes: 11 additions & 1 deletion svg-icons/icons-sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 99e73f0

Please sign in to comment.