import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { Input } from "@ember/component"; import { concat, get, hash } from "@ember/helper"; import { on } from "@ember/modifier"; import { action, computed } from "@ember/object"; import { LinkTo } from "@ember/routing"; import { later } from "@ember/runloop"; import { service } from "@ember/service"; import { eq } from "truth-helpers"; import DButton from "discourse/components/d-button"; import Avatar from "discourse/helpers/bound-avatar-template"; import { popupAjaxError } from "discourse/lib/ajax-error"; import icon from "discourse-common/helpers/d-icon"; import i18n from "discourse-common/helpers/i18n"; import I18n from "discourse-i18n"; import AdminUser from "admin/models/admin-user"; import ComboBox from "select-kit/components/combo-box"; import DTooltip from "float-kit/components/d-tooltip"; export default class AiLlmEditorForm extends Component { @service toasts; @service router; @service dialog; @tracked isSaving = false; @tracked testRunning = false; @tracked testResult = null; @tracked testError = null; @tracked apiKeySecret = true; get selectedProviders() { const t = (provName) => { return I18n.t(`discourse_ai.llms.providers.${provName}`); }; return this.args.llms.resultSetMeta.providers.map((prov) => { return { id: prov, name: t(prov) }; }); } get adminUser() { return AdminUser.create(this.args.model?.user); } get testErrorMessage() { return I18n.t("discourse_ai.llms.tests.failure", { error: this.testError }); } get displayTestResult() { return this.testRunning || this.testResult !== null; } @computed("args.model.provider") get canEditURL() { return this.args.model.provider !== "aws_bedrock"; } get modulesUsingModel() { const usedBy = this.args.model.used_by?.filter((m) => m.type !== "ai_bot"); if (!usedBy || usedBy.length === 0) { return null; } const localized = usedBy.map((m) => { return I18n.t(`discourse_ai.llms.usage.${m.type}`, { persona: m.name, }); }); // TODO: this is not perfectly localized return localized.join(", "); } get seeded() { return this.args.model.id < 0; } get inUseWarning() { return I18n.t("discourse_ai.llms.in_use_warning", { settings: this.modulesUsingModel, count: this.args.model.used_by.length, }); } @computed("args.model.provider") get metaProviderParams() { return ( this.args.llms.resultSetMeta.provider_params[this.args.model.provider] || {} ); } @action async save() { this.isSaving = true; const isNew = this.args.model.isNew; try { await this.args.model.save(); if (isNew) { this.args.llms.addObject(this.args.model); this.router.transitionTo("adminPlugins.show.discourse-ai-llms.index"); } else { this.toasts.success({ data: { message: I18n.t("discourse_ai.llms.saved") }, duration: 2000, }); } } catch (e) { popupAjaxError(e); } finally { later(() => { this.isSaving = false; }, 1000); } } @action async test() { this.testRunning = true; try { const configTestResult = await this.args.model.testConfig(); this.testResult = configTestResult.success; if (this.testResult) { this.testError = null; } else { this.testError = configTestResult.error; } } catch (e) { popupAjaxError(e); } finally { later(() => { this.testRunning = false; }, 1000); } } @action makeApiKeySecret() { this.apiKeySecret = true; } @action toggleApiKeySecret() { this.apiKeySecret = !this.apiKeySecret; } @action delete() { return this.dialog.confirm({ message: I18n.t("discourse_ai.llms.confirm_delete"), didConfirm: () => { return this.args.model .destroyRecord() .then(() => { this.args.llms.removeObject(this.args.model); this.router.transitionTo( "adminPlugins.show.discourse-ai-llms.index" ); }) .catch(popupAjaxError); }, }); } }