UX: QoL impromevements to the admin LLM models page. (#674)

API Key value is secret by default, and we include a link to the AI bot user.
This commit is contained in:
Roman Rizzi 2024-06-19 11:21:21 -03:00 committed by GitHub
parent c4d9fab8e7
commit ed3d5521a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 5 deletions

View File

@ -14,6 +14,8 @@ class LlmModelSerializer < ApplicationSerializer
:enabled_chat_bot, :enabled_chat_bot,
:url_editable :url_editable
has_one :user, serializer: BasicUserSerializer, embed: :object
def url_editable def url_editable
object.url != LlmModel::RESERVED_VLLM_SRV_URL object.url != LlmModel::RESERVED_VLLM_SRV_URL
end end

View File

@ -3,15 +3,18 @@ import { tracked } from "@glimmer/tracking";
import { Input } from "@ember/component"; import { Input } from "@ember/component";
import { on } from "@ember/modifier"; import { on } from "@ember/modifier";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { LinkTo } from "@ember/routing";
import { later } from "@ember/runloop"; import { later } from "@ember/runloop";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import BackButton from "discourse/components/back-button"; import BackButton from "discourse/components/back-button";
import DButton from "discourse/components/d-button"; import DButton from "discourse/components/d-button";
import DToggleSwitch from "discourse/components/d-toggle-switch"; import DToggleSwitch from "discourse/components/d-toggle-switch";
import Avatar from "discourse/helpers/bound-avatar-template";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import icon from "discourse-common/helpers/d-icon"; import icon from "discourse-common/helpers/d-icon";
import i18n from "discourse-common/helpers/i18n"; import i18n from "discourse-common/helpers/i18n";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
import AdminUser from "admin/models/admin-user";
import ComboBox from "select-kit/components/combo-box"; import ComboBox from "select-kit/components/combo-box";
import DTooltip from "float-kit/components/d-tooltip"; import DTooltip from "float-kit/components/d-tooltip";
@ -25,6 +28,7 @@ export default class AiLlmEditor extends Component {
@tracked testRunning = false; @tracked testRunning = false;
@tracked testResult = null; @tracked testResult = null;
@tracked testError = null; @tracked testError = null;
@tracked apiKeySecret = true;
get selectedProviders() { get selectedProviders() {
const t = (provName) => { const t = (provName) => {
@ -36,6 +40,10 @@ export default class AiLlmEditor extends Component {
}); });
} }
get adminUser() {
return AdminUser.create(this.args.model?.user);
}
@action @action
async save() { async save() {
this.isSaving = true; this.isSaving = true;
@ -94,6 +102,16 @@ export default class AiLlmEditor extends Component {
return this.testRunning || this.testResult !== null; return this.testRunning || this.testResult !== null;
} }
@action
makeApiKeySecret() {
this.apiKeySecret = true;
}
@action
toggleApiKeySecret() {
this.apiKeySecret = !this.apiKeySecret;
}
@action @action
delete() { delete() {
return this.dialog.confirm({ return this.dialog.confirm({
@ -177,11 +195,19 @@ export default class AiLlmEditor extends Component {
{{/if}} {{/if}}
<div class="control-group"> <div class="control-group">
<label>{{I18n.t "discourse_ai.llms.api_key"}}</label> <label>{{I18n.t "discourse_ai.llms.api_key"}}</label>
<Input <div class="ai-llm-editor__secret-api-key-group">
class="ai-llm-editor-input ai-llm-editor__api-key" <Input
@type="text" @value={{@model.api_key}}
@value={{@model.api_key}} class="ai-llm-editor-input ai-llm-editor__api-key"
/> @type={{if this.apiKeySecret "password" "text"}}
{{on "focusout" this.makeApiKeySecret}}
/>
<DButton
@action={{this.toggleApiKeySecret}}
@icon="far-eye-slash"
{{on "focusout" this.makeApiKeySecret}}
/>
</div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label>{{I18n.t "discourse_ai.llms.tokenizer"}}</label> <label>{{I18n.t "discourse_ai.llms.tokenizer"}}</label>
@ -213,6 +239,21 @@ export default class AiLlmEditor extends Component {
{{on "click" this.toggleEnabledChatBot}} {{on "click" this.toggleEnabledChatBot}}
/> />
</div> </div>
{{#if @model.user}}
<div class="control-group">
<label>{{i18n "discourse_ai.llms.ai_bot_user"}}</label>
<a
class="avatar"
href={{@model.user.path}}
data-user-card={{@model.user.username}}
>
{{Avatar @model.user.avatar_template "small"}}
</a>
<LinkTo @route="adminUser" @model={{this.adminUser}}>
{{@model.user.username}}
</LinkTo>
</div>
{{/if}}
<div class="control-group ai-llm-editor__action_panel"> <div class="control-group ai-llm-editor__action_panel">
<DButton <DButton
class="ai-llm-editor__test" class="ai-llm-editor__test"

View File

@ -32,4 +32,13 @@
color: var(--success); color: var(--success);
} }
} }
&__api-key {
margin-right: 0.5em;
}
&__secret-api-key-group {
display: flex;
align-items: center;
}
} }

View File

@ -211,6 +211,7 @@ en:
url: "URL of the service hosting the model" url: "URL of the service hosting the model"
api_key: "API Key of the service hosting the model" api_key: "API Key of the service hosting the model"
enabled_chat_bot: "Allow AI Bot" enabled_chat_bot: "Allow AI Bot"
ai_bot_user: "AI Bot User"
save: "Save" save: "Save"
edit: "Edit" edit: "Edit"
saved: "LLM Model Saved" saved: "LLM Model Saved"