import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { concat, fn, hash } from "@ember/helper"; import { action } from "@ember/object"; import { service } from "@ember/service"; import { and, gt } from "truth-helpers"; import Form from "discourse/components/form"; import { popupAjaxError } from "discourse/lib/ajax-error"; import getURL from "discourse/lib/get-url"; import { i18n } from "discourse-i18n"; import AiToolTestModal from "./modal/ai-tool-test-modal"; import RagOptionsFk from "./rag-options-fk"; import RagUploader from "./rag-uploader"; export default class AiToolEditorForm extends Component { @service modal; @service siteSettings; @service dialog; @service router; @service toasts; @tracked uploadedFiles = []; @tracked isSaving = false; PARAMETER_TYPES = [ { name: "string", id: "string" }, { name: "number", id: "number" }, { name: "boolean", id: "boolean" }, { name: "array", id: "array" }, ]; get formData() { const parameters = (this.args.editingModel.parameters ?? []).map( (parameter) => { const mappedParameter = { ...parameter, }; mappedParameter.isEnum = parameter.enum && parameter.enum.length > 0; if (!mappedParameter.isEnum) { delete mappedParameter.enum; } return mappedParameter; } ); return { name: this.args.editingModel.name || "", tool_name: this.args.editingModel.tool_name || "", description: this.args.editingModel.description || "", summary: this.args.editingModel.summary || "", parameters, script: this.args.editingModel.script || "", rag_uploads: this.args.editingModel.rag_uploads || [], }; } @action toggleIsEnum(value, { name, parentName, set }) { if (value) { set(`${parentName}.enum`, [""]); } else { set(`${parentName}.enum`, []); } set(name, value); } @action async save(data) { this.isSaving = true; // we injected a isEnum thing, we need to clean it up const copiedData = JSON.parse(JSON.stringify(data)); if (copiedData.parameters) { copiedData.parameters.forEach((parameter) => { if (!parameter.isEnum) { delete parameter.enum; } delete parameter.isEnum; }); } try { await this.args.model.save(copiedData); this.toasts.success({ data: { message: i18n("discourse_ai.tools.saved") }, duration: "short", }); if (!this.args.tools.any((tool) => tool.id === this.args.model.id)) { this.args.tools.pushObject(this.args.model); } await this.router.replaceWith( "adminPlugins.show.discourse-ai-tools.edit", this.args.model ); } catch (e) { popupAjaxError(e); } finally { this.isSaving = false; } } @action delete() { return this.dialog.confirm({ message: i18n("discourse_ai.tools.confirm_delete"), didConfirm: async () => { await this.args.model.destroyRecord(); this.args.tools.removeObject(this.args.model); this.router.transitionTo("adminPlugins.show.discourse-ai-tools.index"); }, }); } @action updateUploads(addItemToCollection, uploads) { const uniqueUploads = uploads.filter( (upload) => !this.uploadedFiles.some((file) => file.id === upload.id) ); addItemToCollection("rag_uploads", uniqueUploads); this.uploadedFiles = [...this.uploadedFiles, ...uniqueUploads]; } @action removeUpload(form, upload) { this.uploadedFiles = this.uploadedFiles.filter( (file) => file.id !== upload.id ); form.set("rag_uploads", this.uploadedFiles); } @action openTestModal() { this.modal.show(AiToolTestModal, { model: { tool: this.args.editingModel, }, }); } currentParameterSelection(data, index) { return data.parameters[index].type; } get ragUploadsDescription() { return this.siteSettings.rag_images_enabled ? i18n("discourse_ai.rag.uploads.description_with_images") : i18n("discourse_ai.rag.uploads.description"); } @action exportTool() { const exportUrl = `/admin/plugins/discourse-ai/ai-tools/${this.args.model.id}/export.json`; window.location.href = getURL(exportUrl); } }