mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-03-06 09:20:14 +00:00
UX: improve embeddings config styles (#1085)
* WIP: improve embeddings config styles * switch to textarea, fix back button * remove log, update button, fix tests * stree * fix spec * spec fix * remove comment
This commit is contained in:
parent
952e0a51d6
commit
99e73f09ff
@ -77,7 +77,7 @@ class EmbeddingDefinition < ActiveRecord::Base
|
||||
# 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: "<=>",
|
||||
@ -91,7 +91,7 @@ class EmbeddingDefinition < ActiveRecord::Base
|
||||
},
|
||||
{
|
||||
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: "<=>",
|
||||
@ -105,7 +105,7 @@ class EmbeddingDefinition < ActiveRecord::Base
|
||||
},
|
||||
{
|
||||
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: "<=>",
|
||||
|
@ -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";
|
||||
@ -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";
|
||||
@ -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,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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">
|
||||
<DButton
|
||||
@action={{this.configurePreset}}
|
||||
@label="discourse_ai.tools.next.title"
|
||||
class="ai-embedding-editor__next"
|
||||
/>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if this.editingModel.isNew}}
|
||||
<DButton
|
||||
@action={{this.resetForm}}
|
||||
@label="back_button"
|
||||
@icon="chevron-left"
|
||||
class="btn-flat back-button"
|
||||
/>
|
||||
{{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
|
||||
@ -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">
|
||||
@ -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">
|
||||
@ -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|}}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
@ -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:
|
||||
|
@ -13,10 +13,9 @@ RSpec.describe "Managing Embeddings configurations", type: :system, js: true do
|
||||
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()
|
||||
|
||||
@ -43,12 +42,10 @@ RSpec.describe "Managing Embeddings configurations", type: :system, js: true do
|
||||
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
|
||||
@ -63,8 +60,8 @@ RSpec.describe "Managing Embeddings configurations", type: :system, js: true do
|
||||
|
||||
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)
|
||||
|
@ -13,4 +13,14 @@
|
||||
<symbol id="discourse-table-sparkles" viewBox="0 0 512 512">
|
||||
<path d="M448 309.64V413H64V290h190c12.23 0 18.46-14.71 9.94-23.48-7.56-7.78-14.48-16.2-20.66-25.16-5.36-7.77-14.24-12.36-23.69-12.36H64V93h130c10.65 0 20.14-6.92 23.18-17.12a193.4 193.4 0 0 1 9.74-25.76c4.56-9.86-2.77-21.12-13.63-21.12H64C28.65 29 0 57.65 0 93v320c0 35.35 28.65 64 64 64h384c35.35 0 64-28.65 64-64V263.8c0-9.16-10.7-14.14-17.7-8.25a194.056 194.056 0 0 1-25.76 18.32c-12.66 7.53-20.53 21.05-20.53 35.77Z"/><path d="M247.46 122.15c-6.45 2.44-10.75 8.6-10.75 15.49s4.3 13.05 10.75 15.49l81.01 30.4 30.4 81.01c2.44 6.45 8.6 10.75 15.49 10.75s13.05-4.3 15.49-10.75l30.4-81.01 81.01-30.4c6.45-2.44 10.75-8.6 10.75-15.49s-4.3-13.05-10.75-15.49l-81.01-30.4-30.4-81.01c-2.44-6.45-8.6-10.75-15.49-10.75s-13.05 4.3-15.49 10.75l-30.4 81.01-81.01 30.4Z"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<!-- "Discourse Spaceship Operator" is a Discourse derivative of https://fontawesome.com/icons/equals?f=classic&s=solid and https://fontawesome.com/icons/less-than?f=classic&s=solid -->
|
||||
<symbol id="discourse-spaceship-operator" viewBox="0 0 448 512">
|
||||
<path d="M132.3 195.8c2.7 5.5.5 12.2-5 14.9L36 256.4l91.3 45.7c5.5 2.7 7.7 9.4 5 14.9s-9.4 7.7-14.9 5L6.2 266.4c-3.8-1.9-6.2-5.7-6.2-9.9s2.4-8.1 6.2-9.9L117.5 191c5.5-2.7 12.2-.5 14.9 5ZM315.7 317c-2.7-5.5-.5-12.2 5-14.9l91.3-45.7-91.3-45.7c-5.5-2.7-7.7-9.4-5-14.9s9.4-7.7 14.9-5l111.3 55.6c3.8 1.9 6.2 5.7 6.2 9.9s-2.4 8.1-6.2 9.9l-111.3 55.6c-5.5 2.7-12.2.5-14.9-5ZM169.2 211.5c-5.6 0-10.1 5.3-10.1 11.8s4.5 11.8 10.1 11.8h110.9c5.6 0 10.1-5.3 10.1-11.8s-4.5-11.8-10.1-11.8H169.2Zm0 65.9c-5.6 0-10.1 5.3-10.1 11.8s4.5 11.8 10.1 11.8h110.9c5.6 0 10.1-5.3 10.1-11.8s-4.5-11.8-10.1-11.8H169.2Z"/>
|
||||
</symbol>
|
||||
|
||||
<!-- "Discourse Negative Inner Product" is a Discourse derivative of https://fontawesome.com/icons/hashtag?f=classic&s=solid and https://fontawesome.com/icons/less-than?f=classic&s=solid -->
|
||||
<symbol id="discourse-negative-inner-product" viewBox="0 0 448 512">
|
||||
<path d="M132.3 195.8c2.7 5.5.5 12.2-5 14.9L36 256.4l91.3 45.7c5.5 2.7 7.7 9.4 5 14.9s-9.4 7.7-14.9 5L6.2 266.4c-3.8-1.9-6.2-5.7-6.2-9.9s2.4-8.1 6.2-9.9L117.5 191c5.5-2.7 12.2-.5 14.9 5ZM315.7 317c-2.7-5.5-.5-12.2 5-14.9l91.3-45.7-91.3-45.7c-5.5-2.7-7.7-9.4-5-14.9s9.4-7.7 14.9-5l111.3 55.6c3.8 1.9 6.2 5.7 6.2 9.9s-2.4 8.1-6.2 9.9l-111.3 55.6c-5.5 2.7-12.2.5-14.9-5ZM211.9 187.6c5.2.9 8.8 5.8 7.9 11.1l-3 17.7h28.6l3.5-20.9c.9-5.2 5.8-8.8 11.1-7.9 5.2.9 8.8 5.8 7.9 11.1l-2.9 17.7h17.5c5.3 0 9.6 4.3 9.6 9.6s-4.3 9.6-9.6 9.6h-20.7l-6.4 38.5h17.5c5.3 0 9.6 4.3 9.6 9.6s-4.3 9.6-9.6 9.6h-20.7l-3.5 20.9c-.9 5.2-5.8 8.8-11.1 7.9s-8.8-5.8-7.9-11.1l3-17.7h-28.6l-3.5 20.9c-.9 5.2-5.8 8.8-11.1 7.9-5.2-.9-8.8-5.8-7.9-11.1l2.9-17.7H167c-5.3 0-9.6-4.3-9.6-9.6s4.3-9.6 9.6-9.6h20.7l6.4-38.5h-17.5c-5.3 0-9.6-4.3-9.6-9.6s4.3-9.6 9.6-9.6h20.7l3.5-20.9c.9-5.2 5.8-8.8 11.1-7.9Zm1.7 48-6.4 38.5h28.6l6.4-38.5h-28.6Z"/>
|
||||
</symbol>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.5 KiB |
Loading…
x
Reference in New Issue
Block a user