diff --git a/packages/prompt-tuning/__stories__/prompt-tuning.mdx b/packages/prompt-tuning/__stories__/prompt-tuning.mdx new file mode 100644 index 00000000..4add9266 --- /dev/null +++ b/packages/prompt-tuning/__stories__/prompt-tuning.mdx @@ -0,0 +1,53 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../../globals/internal/storybook-cdn'; +import * as PromptTuningStories from './prompt-tuning.stories'; +import packageJson from '../package.json'; + + + +# Prompt Tuning + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon-labs/tree/main/packages/prompt-tuning/examples/prompt-tuning) +> example implementation. + +[![Edit carbon-labs](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon-labs/tree/main/packages/prompt-tuning/examples/prompt-tuning) + +## Overview + +The prompt-tuning component. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon-labs/ai-prompt-tuning/es/index.js'; +``` + +### Styles + +You'll also need to import the theming tokens from `@carbon/styles` either from +npm or from our CDN helpers. Checkout our Stackblitz example above to see how +that is implemented. + +{/* prettier-ignore */} +{`${cdnJs({ components: ['prompt-tuning'] },packageJson)}`} +{`${cdnCss()}`} + +### HTML + +```html + + PromptTuning text + +``` + +### <clabs-prompt-tuning> attributes and properties + + diff --git a/packages/prompt-tuning/__stories__/prompt-tuning.stories.js b/packages/prompt-tuning/__stories__/prompt-tuning.stories.js new file mode 100644 index 00000000..3a8d482b --- /dev/null +++ b/packages/prompt-tuning/__stories__/prompt-tuning.stories.js @@ -0,0 +1,211 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ +import '../components/prompt-tuning/prompt-tuning'; +import { html } from 'lit'; +import { action } from '@storybook/addon-actions'; + +import '@carbon/web-components/es/components/button/index.js'; +import semantic_search_view from './semantic_search_view.json'; + +export default { + title: 'Components/Prompt Tuning/Prompt Tuning', + component: 'clabs-prompt-tuning', +}; + +const defaultArgs = { + promptSamples: semantic_search_view.samples, + viewList: [ + 'task_view', + 'semantic_search_view', + 'collections_view', + 'semantic_querying_view', + 'table_details_view', + 'table_upload_view', + 'visualization_view', + 'table_expansion_view', + 'glossary_view', + 'table_comparison_view', + 'causal_interference_view', + ], + currentView: { + name: 'semantic_search_view', + contextVariables: ['table_ids'], + parameters: ['mode', 'question', 'table_ids'], + }, + onSaveRename: action('save-rename'), + onCloseTag: action('close-tag'), + onAddContextVariable: action('add-context-variable'), + onAddParameter: action('add-parameter'), + onSavePrompt: action('save-prompt'), + onDeletePrompt: action('delete-prompt'), + onChangeView: action('change-view'), + onAddPrompt: action('add-prompt'), + isListModalOpen: true, +}; + +/* Default controls */ +const defaultControls = { + isListModalOpen: { + name: 'open', + control: { type: 'boolean' }, + description: 'Whether the tuning prompts modal is open or not', + table: { + category: '', + defaultValue: { summary: true }, + }, + }, + promptSamples: { + control: { type: 'object' }, + description: 'Current view data', + table: { + defaultValue: { + summary: 'Using a JSON example from semantic search view for storybook', + }, + }, + }, + currentView: { + control: { type: 'object' }, + description: 'Name, context variables, and parameters in the current view', + table: { + defaultValue: { + summary: 'Using a JSON example with semantic search view for storybook', + }, + }, + }, + viewList: { + control: { type: 'object' }, + description: 'List of views', + table: { + defaultValue: { + summary: 'Using an example of a list of views for storybook', + }, + }, + }, + onAddContextVariable: { + action: 'add-context-variable', + description: + 'Fires when user saves new context variable for the current view', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onAddParameter: { + action: 'add-parameter', + description: 'Fires when user saves new parameter for the current view', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onChangeView: { + action: 'change-view', + description: + 'Fires when user chooses a different view in the select dropdown', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onCloseTag: { + action: 'change-view', + description: + 'Fires when user clicks the X for the current view context variable or parameter', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onDeletePrompt: { + action: 'delete-prompt', + description: + 'Fires when user clicks the trash icon next to a prompt table row', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onSavePrompt: { + action: 'save-prompt', + description: 'Fires when user edits a prompt and saves the changes', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onSaveRename: { + action: 'save-rename', + description: 'Fires when user renames the current view and saves changes', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + onAddPrompt: { + action: 'save-rename', + description: 'Fires when user adds a new prompt', + table: { + category: 'Events', + defaultValue: { summary: 'function' }, + }, + }, + + isEditModalOpen: { + table: { + disable: true, + }, + }, + text: { + table: { + disable: true, + }, + }, +}; + +/** + * More on writing stories with args: https://storybook.js.org/docs/web-components/writing-stories/args + * + * @type {{args: {label: string}, render: (function(*): TemplateResult<1>)}} + */ +export const Default = { + argTypes: defaultControls, + args: defaultArgs, + /** + * Renders the template for Storybook + * @param {string} args.content - content to generate from + * @returns {TemplateResult<1>} + */ + render: ({ + isListModalOpen, + promptSamples, + viewList, + currentView, + onSaveRename, + onCloseTag, + onAddContextVariable, + onAddParameter, + onSavePrompt, + onDeletePrompt, + onChangeView, + onAddPrompt, + }) => + html` `, +}; diff --git a/packages/prompt-tuning/__stories__/semantic_search_view.json b/packages/prompt-tuning/__stories__/semantic_search_view.json new file mode 100644 index 00000000..73221895 --- /dev/null +++ b/packages/prompt-tuning/__stories__/semantic_search_view.json @@ -0,0 +1,291 @@ +{ + "samples": [ + { + "id": 20123, + "user_id": "demo", + "input": { + "input": "I'd like to see the quality of this table.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[BANKDEMO.SAVINGS_ACCOUNTS]" + } + }, + "output": { + "output": "Alright, here are some important Data Quality metrics for this table.", + "view_id": "table_details_view", + "parameters": { + "mode": "quality", + "question": "", + "table_ids": "[BANKDEMO.SAVINGS_ACCOUNTS]" + } + } + }, + { + "id": 20124, + "user_id": "demo", + "input": { + "input": "Can you show me the schema for this table?", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.ORGANIZATION_CST_LOYALTY_FACT]" + } + }, + "output": { + "output": "No problem, here is the schema of your table.", + "view_id": "table_details_view", + "parameters": { + "mode": "schema", + "question": "", + "table_ids": "[CSTINSIGHT.ORGANIZATION_CST_LOYALTY_FACT]" + } + } + }, + { + "id": 20125, + "user_id": "demo", + "input": { + "input": "Show me the data of this table.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[PMT_RISK.BUILDING_TYPE]" + } + }, + "output": { + "output": "Alright, here you can take a look at data in this table.", + "view_id": "table_details_view", + "parameters": { + "mode": "data", + "question": "", + "table_ids": "[PMT_RISK.BUILDING_TYPE]" + } + } + }, + { + "id": 20135, + "user_id": "demo", + "input": { + "input": "i'd like to see the quality of this table.", + "view_id": "semantic_search_view", + "context_variables": {} + }, + "output": { + "output": "You did not select a table yet.", + "view_id": "semantic_search_view", + "parameters": {} + } + }, + { + "id": 20136, + "user_id": "demo", + "input": { + "input": "What can I join this table with?", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.CUSTOMER]" + } + }, + "output": { + "output": "Let's see if we have some joinable tables in the Lakehouse.", + "view_id": "table_expansion_view", + "parameters": { + "keyword": "", + "table_ids": "[CSTINSIGHT.CUSTOMER]" + } + } + }, + { + "id": 20142, + "user_id": "demo", + "input": { + "input": "I'd like to add more geographic context to this table.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[PMT_RISK.BUILDING_TYPE]" + } + }, + "output": { + "output": "Alright, let's see if we find joinable tables with geographic data.", + "view_id": "table_expansion_view", + "parameters": { + "keyword": "geography", + "table_ids": "[PMT_RISK.BUILDING_TYPE]" + } + } + }, + { + "id": 20143, + "user_id": "demo", + "input": { + "input": "I'd like to add residence location data to this.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CUSTOM.b1c0f860-b1d7-43c2-a1a2-4807e78ed15b]" + } + }, + "output": { + "output": "Alright, let's look for compatible tables that contain this kind of data.", + "view_id": "table_expansion_view", + "parameters": { + "keyword": "residence location", + "table_ids": "[CUSTOM.b1c0f860-b1d7-43c2-a1a2-4807e78ed15b]" + } + } + }, + { + "id": 20156, + "user_id": "demo", + "input": { + "input": "I would like to see the annotations for this table.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.PERSON]" + } + }, + "output": { + "output": "Sure, here are the annotations and also you can provide your feedback on these.", + "view_id": "collection_annotation_view", + "parameters": { + "table_ids": "[CSTINSIGHT.PERSON]" + } + } + }, + { + "id": 20161, + "user_id": "demo", + "input": { + "input": "Show me the details of table PMT_RISK.BUILDING_TYPE.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[BANKDEMO.ACCOUNTS]" + } + }, + "output": { + "output": "Alright, pulling up this table for you.", + "view_id": "table_details_view", + "parameters": { + "question": "", + "mode": "schema", + "table_ids": "[PMT_RISK.BUILDING_TYPE]" + } + } + }, + { + "id": 20162, + "user_id": "demo", + "input": { + "input": "I would like to review the concept annotations of these tables.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.CUSTOMER,BANKDEMO.ACCOUNTS]" + } + }, + "output": { + "output": "No problem, here you can take a look at how the columns have been mapped to glossary concepts.", + "view_id": "collection_annotation_view", + "parameters": { + "table_ids": "[CSTINSIGHT.CUSTOMER,BANKDEMO.ACCOUNTS]" + } + } + }, + { + "id": 20177, + "user_id": "demo", + "input": { + "input": "Can I improve my sales strategy using this?", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.PRODUCT]" + } + }, + "output": { + "output": "Alright, let me try to create a policy based on the customer table.", + "view_id": "causal_inference_view", + "parameters": { + "keyword": "", + "question": "I want to improve the sales strategy.", + "table_ids": "[CSTINSIGHT.PRODUCT]" + } + } + }, + { + "id": 20185, + "user_id": "demo", + "input": { + "input": "I have a question about this table.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.INDIVIDUAL_CST_CHURN_FACT]", + "keyword": "customer churn" + } + }, + "output": { + "output": "Sure, what would you like to know about it?", + "view_id": "semantic_search_view", + "parameters": { + "keyword": "customer churn" + } + } + }, + { + "id": 20186, + "user_id": "demo", + "input": { + "input": "Who is the customer with highest net worth?", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.CUSTOMER]", + "keyword": "customer churn" + } + }, + "output": { + "output": "Let me check whether if I can find the answer to this by querying the lakehouse for you.", + "view_id": "semantic_querying_view", + "parameters": { + "table_ids": "[CSTINSIGHT.CUSTOMER]", + "mode": "sql", + "question": "Who is the customer with highest net worth?" + } + } + }, + { + "id": 20190, + "user_id": "demo", + "input": { + "input": "This looks interesting. What kinda products do we gave here?", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "[CSTINSIGHT.PRODUCT]" + } + }, + "output": { + "output": "I'm gonna try to inquire about this in the lakehouse for you.", + "view_id": "semantic_querying_view", + "parameters": { + "keyword": "", + "table_ids": "[CSTINSIGHT.PRODUCT]", + "mode": "sql", + "question": "What kinda products do we gave here?" + } + } + }, + { + "id": 20196, + "user_id": "demo", + "input": { + "input": "I have a question about CSTINSIGHT.INDIVIDUAL_CST_CHURN_FACT.", + "view_id": "semantic_search_view", + "context_variables": { + "table_ids": "", + "keyword": "customer churn" + } + }, + "output": { + "output": "Sure, what would you like to know about it?", + "view_id": "semantic_search_view", + "parameters": { + "keyword": "customer churn" + } + } + } + ] +} diff --git a/packages/prompt-tuning/components/prompt-tuning/prompt-tuning.ts b/packages/prompt-tuning/components/prompt-tuning/prompt-tuning.ts new file mode 100644 index 00000000..4dbb9111 --- /dev/null +++ b/packages/prompt-tuning/components/prompt-tuning/prompt-tuning.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { customElement } from 'lit/decorators.js'; +import { settings } from '@carbon-labs/utilities/es/settings/index.js'; +import { PromptTuning } from './src/prompt-tuning.js'; +import { TemplateResult } from 'lit'; +import { promptTuningTemplate } from './src/prompt-tuning.template.js'; + +const { stablePrefix: clabsPrefix } = settings; + +/** + * Component extending the PromptTuning component + * + * @element clabs-prompt-tuning + */ +@customElement(`${clabsPrefix}-prompt-tuning`) +class CLABSPromptTuning extends PromptTuning { + /** + * Renders the template while passing in class functionality + */ + render(): TemplateResult<1> { + return promptTuningTemplate(this); + } +} + +export default CLABSPromptTuning; diff --git a/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.scss b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.scss new file mode 100644 index 00000000..f36ee12c --- /dev/null +++ b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.scss @@ -0,0 +1,82 @@ +/** + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +$css--plex: true !default; + +@use '../../../../../globals/scss/vars' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/type' as *; + +:host(#{$clabs-prefix}-prompt-tuning) { + .#{$clabs-prefix}--heading-container { + padding: 0; + } + .#{$clabs-prefix}--heading, + .#{$clabs-prefix}--enter-new { + display: flex; + } + .#{$clabs-prefix}--heading-tune-prompts { + min-inline-size: max-content; + } + .#{$clabs-prefix}--view-dropdown { + max-inline-size: min-content; + } + .#{$clabs-prefix}--rename { + flex-grow: 1; + } + .#{$clabs-prefix}--header-view-info { + display: flex; + } + .#{$clabs-prefix}--header-context-variables { + flex: 1 1 50%; + } + .#{$clabs-prefix}--header-parameters { + flex: 1 1 25%; + } + + .#{$clabs-prefix}--add-context-variable-tag, + .#{$clabs-prefix}--add-parameter-tag { + cursor: pointer; + } + + .#{$clabs-prefix}--add-context-variable-tag:hover, + .#{$clabs-prefix}--add-parameter-tag:hover { + background-color: #636363; + } + + .#{$clabs-prefix}--table-actions { + min-inline-size: 96px; + } + .#{$clabs-prefix}--prompt-edit-form { + display: flex; + justify-content: space-between; + + h4 { + padding: 0; + margin: 1rem 0 0.5rem; + font-size: 1.25rem; + font-weight: 400; + letter-spacing: 0; + line-height: 1.4; + } + + .#{$clabs-prefix}--edit-form-item { + display: inline-block; + margin-block-start: 10px; + } + + .#{$clabs-prefix}--edit-input { + flex: 1 1 50%; + margin-inline-end: 24px; + } + + .#{$clabs-prefix}--edit-output { + flex: 1 1 50%; + margin-inline-start: 24px; + } + } +} diff --git a/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.template.ts b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.template.ts new file mode 100644 index 00000000..42476889 --- /dev/null +++ b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.template.ts @@ -0,0 +1,537 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { settings } from '@carbon-labs/utilities/es/settings/index.js'; +const { stablePrefix: clabsPrefix } = settings; +import '@carbon/web-components/es/components/modal/index.js'; +import '@carbon/web-components/es/components/data-table/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +import '@carbon/web-components/es/components/form-group/index.js'; +import Edit16 from '@carbon/web-components/es/icons/edit/16.js'; +import TrashCan16 from '@carbon/web-components/es/icons/trash-can/16.js'; +import Add16 from '@carbon/web-components/es/icons/add/16.js'; +import RequestQuote16 from '@carbon/web-components/es/icons/request-quote/16.js'; +import Close16 from '@carbon/web-components/es/icons/close/16.js'; +import Checkmark16 from '@carbon/web-components/es/icons/checkmark/16.js'; + +import '@carbon/web-components/es/components/tag/index.js'; + +import '@carbon/web-components/es/components/text-input/index.js'; +import '@carbon/web-components/es/components/select/index.js'; +import '@carbon/web-components/es/components/form/index.js'; +import '@carbon/web-components/es/components/tooltip/index.js'; + +/** + * Render HTML rows + * + * @param {object} customElementClass Class functionality for the custom element + * @returns {TemplateResult<1>} Lit html template + */ +function getHTMLRows(customElementClass) { + const { + promptSamples: promptSamples, + _onEditButtonClick: onEditButtonClick, + onDeleteButtonClick: onDeleteButtonClick, + } = customElementClass; + + return html` + ${promptSamples.map( + (item) => + html` + ${item.input.input} + ${Object.keys(item.input.context_variables).length > 0 + ? html`${Object.entries(item.input.context_variables).map( + (item) => + item.length > 0 + ? html` + +
+ ${item[1]} +
+ + ${item[0]}: ${item[1]} + +
+ ` + : html`` + )}` + : html``} +
+ ${item.output.output} + ${item.output.view_id} + ${Object.keys(item.output.parameters).length > 0 + ? html`${Object.entries(item.output.parameters).map((item) => + item.length > 0 + ? html` + +
+ ${item[1]} +
+ + ${item[0]}: ${item[1]} + +
+ ` + : html`` + )}` + : html``} +
+ + ${Edit16()} + ${TrashCan16()} + +
` + )} + `; +} + +/** + * Render views for select + * + * @param {object} customElementClass Class functionality for the custom element + * @returns {TemplateResult<1>} Lit html template + */ +function getSelectViews(customElementClass) { + const { viewList: viewList } = customElementClass; + + const views = viewList.map((view) => { + return html`${view}`; + }); + + return views; +} + +/** + * Render HTML rows + * + * @param {object} customElementClass Class functionality for the custom element + * @returns {TemplateResult<1>} Lit html template + */ +function getEditModal(customElementClass) { + const { + viewList: viewList, + _currentPrompt: currentPrompt, + _currentContextVariables: currentContextVariables, + _currentResponse: currentResponse, + _currentResponseView: currentResponseView, + _currentParameters: currentParameters, + isEditModalOpen, + _onEditModalClose: onEditModalClose, + _onEditModalCancel: onEditModalCancel, + onSavePrompt: onSavePrompt, + triggerSubmit: triggerSubmit, + _isNewPrompt: isNewPrompt, + currentView: currentView, + } = customElementClass; + + let modalHeader, selectedView, contextVariables, parameters; + + if (isNewPrompt) { + modalHeader = `Add new prompt for ${currentView.name}`; + selectedView = currentView.name; + contextVariables = + currentView.contextVariables.length <= 0 + ? html`
+ This intent/view does not provide any context variables. +
` + : currentView.contextVariables.map( + (variable) => html` + ` + ); + parameters = + currentView.parameters.length <= 0 + ? html`
This intent/view does not provide any parameters.
` + : currentView.parameters.map( + (parameter) => html` + ` + ); + } else { + modalHeader = 'Edit prompt'; + selectedView = currentResponseView; + contextVariables = + Object.keys(currentContextVariables).length <= 0 + ? html`
+ This intent/view does not provide any context variables. +
` + : Object.entries(currentContextVariables).map( + ([key, value]) => html` + ` + ); + parameters = + Object.keys(currentParameters).length <= 0 + ? html`
This intent/view does not provide any parameters.
` + : Object.entries(currentParameters).map( + ([key, value]) => html` + ` + ); + } + + return html` + + + ${modalHeader} + + + + +
+
+ + + +

Context variables

+ ${contextVariables} +
+
+ + + + + ${viewList.map( + (view) => + html`${view}` + )} + + +

Expected intent/view parameters

+ ${parameters} +
+
+
+
+
+ + Cancel + Save + +
`; +} + +/** + * Lit template for prompt tuning + * + * @param {object} customElementClass Class functionality for the custom element + * @returns {TemplateResult<1>} Lit html template + */ +export function promptTuningTemplate(customElementClass) { + const { + currentView: currentView, + isListModalOpen, + _onListModalClose: onListModalClose, + _showRename: showRename, + _showAddContextVariable: showAddContextVariable, + _showAddParameter: showAddParameter, + _toggleRename: toggleRename, + _toggleAddContextVariable: toggleAddContextVariable, + _toggleAddParameter: toggleAddParameter, + addContextVariable: addContextVariable, + addParameter: addParameter, + _handleContextVariableInput: handleContextVariableInput, + _handleParameterInput: handleParameterInput, + onSaveRename: onSaveRename, + _handleNameInput: handleNameInput, + onChangeView: onChangeView, + _onNewPrompt: onNewPrompt, + handleCloseTag: handleCloseTag, + } = customElementClass; + + return html`
+ + + + +
+
+ Tune prompts for +
+ ${!showRename + ? html` + ${getSelectViews(customElementClass)} + + + +
+ + ${RequestQuote16()} + +
+ + Rename intent/view +
` + : html` +
+ + + + +
+ +
+ + ${Close16()} + +
+ + Cancel rename +
+ +
+ + ${Checkmark16()} + +
+ + Save rename +
+ `} +
+ +
+
+
Context Variables:
+ ${currentView.contextVariables.length <= 0 + ? html`
+ This intent/view does not provide any parameters. +
` + : currentView.contextVariables.map( + (variable) => html` + ${variable} + ` + )} + ${!showAddContextVariable + ? html` + ${Add16({ slot: 'icon' })} Add context variable + ` + : html` +
+ + + + + +
+ + ${Close16()} + +
+ + Cancel +
+ +
+ + ${Checkmark16()} + +
+ + Save new context variable +
+
+ `} +
+
+
Parameters:
+ + ${currentView.parameters.length <= 0 + ? html`
+ This intent/view does not provide any parameters. +
` + : currentView.parameters.map( + (parameter) => html` + ${parameter} + ` + )} + ${!showAddParameter + ? html`${Add16()} Add parameter + ` + : html`
+ + + + + +
+ + ${Close16()} + +
+ + Cancel +
+ +
+ + ${Checkmark16()} + +
+ + Save new parameter +
+
`} +
+
+
+
+ + + + + Prompt + Response + Intent/View + Actions + + + + ${getHTMLRows(customElementClass)} + + + + Add new prompt + +
+ + ${getEditModal(customElementClass)} +
`; +} diff --git a/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.ts b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.ts new file mode 100644 index 00000000..a795e876 --- /dev/null +++ b/packages/prompt-tuning/components/prompt-tuning/src/prompt-tuning.ts @@ -0,0 +1,412 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { settings } from '@carbon-labs/utilities/es/settings/index.js'; +const { stablePrefix: clabsPrefix } = settings; + +// @ts-ignore +import styles from './prompt-tuning.scss?inline'; +/** + * Input component using search typeahead api + */ +export class PromptTuning extends LitElement { + static styles = styles; + + /** + * Prompt samples data + */ + @property({ attribute: 'promptSamples', type: Array }) + promptSamples; + + /** + * Whether the prompt list modal is open or not + */ + @property({ type: Boolean }) + isListModalOpen = true; + + /** + * Whether the prompt edit modal is open or not + */ + @property({ type: Boolean }) + isEditModalOpen = false; + + /** + * New view name + */ + @property({ type: String }) + private _newName = ''; + + /** + * Current prompt + */ + @property({ type: String }) + // @ts-ignore: Used in template.ts + private _currentPrompt = ''; + + /** + * Current context variables + */ + @property({ type: Object }) + // @ts-ignore: Used in template.ts + private _currentContextVariables = {}; + + /** + * Current response + */ + @property({ type: String }) + // @ts-ignore: Used in template.ts + private _currentResponse = ''; + + /** + * Current response view + */ + @property({ type: String }) + // @ts-ignore: Used in template.ts + private _currentResponseView = ''; + + /** + * Current parameters + */ + @property({ type: Object }) + // @ts-ignore: Used in template.ts + private _currentParameters = {}; + + /** + * Current response view + */ + @property({ type: Boolean }) + private _showRename = false; + + /** + * Show add context variable + */ + @property({ type: Boolean }) + private _showAddContextVariable = false; + + /** + * Show add parameter + */ + @property({ type: Boolean }) + private _showAddParameter = false; + + /** + * New context variable to add + */ + @property({ type: String }) + private _newContextVariable = ''; + + /** + * New parameter to add + */ + @property({ type: String }) + private _newParameter = ''; + + /** + * Whether to show new prompt as opposed to edit prompt + */ + @property({ type: Boolean }) + private _isNewPrompt = false; + + /** + * Method for closing the Prompt List Modal + */ + _onListModalClose() { + this.isListModalOpen = false; + } + + /** + * Method for closing the Prompt Edit Modal + */ + _onEditModalClose() { + this._currentPrompt = ''; + this._currentContextVariables = {}; + this._currentResponse = ''; + this._currentResponseView = ''; + this._currentParameters = {}; + this.isEditModalOpen = false; + this._isNewPrompt = false; + } + + /** + * Method for clicking the Cancel button on the Prompt Edit Modal + */ + _onEditModalCancel() { + this._currentPrompt = ''; + this._currentContextVariables = {}; + this._currentResponse = ''; + this._currentResponseView = ''; + this._currentParameters = {}; + this.isEditModalOpen = false; + this.isListModalOpen = true; + this._isNewPrompt = false; + } + + /** + * Method for clicking a table row Edit button + * @param {string} prompt prompt + * @param {Object} contextVariables context variables + * @param {string} response response + * @param {string} responseView response view + * @param {Object} parameters parameters + */ + _onEditButtonClick( + prompt, + contextVariables, + response, + responseView, + parameters + ) { + this.isListModalOpen = false; + this.isEditModalOpen = true; + this._currentPrompt = prompt; + this._currentContextVariables = contextVariables; + this._currentResponse = response; + this._currentResponseView = responseView; + this._currentParameters = parameters; + } + + /** + * Method when Add new prompt is clicked + */ + _onNewPrompt() { + this.isListModalOpen = false; + this.isEditModalOpen = true; + this._isNewPrompt = true; + } + + /** + * Method for clicking a table row Delete button + * @param {string} prompt prompt + * @param {Object} contextVariables context variables + * @param {string} response response + * @param {string} responseView response view + * @param {Object} parameters parameters + */ + onDeleteButtonClick( + prompt, + contextVariables, + response, + responseView, + parameters + ) { + this.dispatchEvent( + new CustomEvent('delete-prompt', { + detail: { + message: `Deleting prompt.`, + prompt: { + prompt: prompt, + contextVariables: contextVariables, + response: response, + intentView: responseView, + parameters: parameters, + }, + }, + }) + ); + } + + /** + * Method for toggling view rename + */ + _toggleRename() { + this._showRename = !this._showRename; + } + + /** + * Method for toggling if add context variable is clicked + */ + _toggleAddContextVariable() { + this._showAddContextVariable = !this._showAddContextVariable; + } + + /** + * Method for toggling if add parameter is clicked + */ + _toggleAddParameter() { + this._showAddParameter = !this._showAddParameter; + } + + /** + * Event handler to handle new view name input field updates + * @param {event} event event + */ + _handleNameInput(event) { + this._newName = event.target.value; + } + + /** + * fire event when view rename is saved + * + */ + onSaveRename() { + this.dispatchEvent( + new CustomEvent('save-rename', { + detail: { + message: `Rename saved: ${this._newName}`, + newName: this._newName, + }, + }) + ); + this._toggleRename(); + } + + /** + * Handle when close button on tag is clicked + * @param {event} event event + */ + handleCloseTag(event) { + this.dispatchEvent( + new CustomEvent('close-tag', { + detail: { + message: `Tag closed: ${event.target.title}`, + closedTag: event.target.title, + tagType: event.target.ariaLabel, + }, + }) + ); + } + + /** + * fire event when new context variable is added to the view + * + */ + addContextVariable() { + this.dispatchEvent( + new CustomEvent('add-context-variable', { + detail: { + message: `Add context variable: ${this._newContextVariable}`, + newContextVariable: this._newContextVariable, + }, + }) + ); + this._toggleAddContextVariable(); + } + + /** + * fire event when new parameter is added to the view + * + */ + addParameter() { + this.dispatchEvent( + new CustomEvent('add-parameter', { + detail: { + message: `Add parameter: ${this._newParameter}`, + newParameter: this._newParameter, + }, + }) + ); + this._toggleAddParameter(); + } + + /** + * Event handler to handle new context variable name + * @param {event} event event + */ + _handleContextVariableInput(event) { + this._newContextVariable = event.target.value; + } + + /** + * Event handler to handle new parameter name + * @param {event} event event + */ + _handleParameterInput(event) { + this._newParameter = event.target.value; + } + + /** + * fire event when save button when editing prompt is triggered + * + */ + triggerSubmit() { + const form = this.shadowRoot?.getElementById( + `${clabsPrefix}--edit-prompt-form` + ); + if (form) { + form.dispatchEvent(new Event('submit')); + } + this._onEditModalCancel(); + } + + /** + * Event handler when prompt edit is saved + * @param {event} event event + */ + onSavePrompt(event) { + event.preventDefault(); + const form = event.target; + + if (form) { + const className = `.${clabsPrefix}--edit-form-item`; + const items = form.querySelectorAll(className); + const data = {}; + items.forEach((item) => { + let key = ''; + + if (item.classList.contains(`${clabsPrefix}--edit-context-variable`)) { + key += '(context variable) '; + } else if (item.classList.contains(`${clabsPrefix}--edit-parameter`)) { + key += '(parameter) '; + } + + if (item.tagName === 'CDS-TEXT-INPUT') { + key += item.__label; + data[key] = item._value; + } else if (item.tagName === 'CDS-SELECT') { + key += item.__labelText; + data[key] = item.__value; + } else { + key += item.__label; + data[key] = item._value; + } + }); + + if (this._isNewPrompt) { + this.dispatchEvent( + new CustomEvent('add-prompt', { + detail: { formData: data }, + }) + ); + } else { + this.dispatchEvent( + new CustomEvent('save-prompt', { + detail: { formData: data }, + }) + ); + } + } + } + + /** + * Event handler to handle user changing current view + * @param {event} event event + */ + onChangeView(event) { + this.dispatchEvent( + new CustomEvent('change-view', { + detail: { newView: event.target.value }, + }) + ); + } + + // /** + // * updated - check changed properties + // * @param {object} changedProperties - LIT object denoting changed attributes + // */ + // updated(changedProperties) { + // console.log(`updated`); + // super.updated(changedProperties); + // if (changedProperties.has('isListModalOpen')) { + // console.log(`updated isListModalOpen: ${this.isListModalOpen}`); + // // this.isListModalOpen = this.isListModalOpen; + // } + // } +} diff --git a/packages/prompt-tuning/examples/prompt-tuning/.gitignore b/packages/prompt-tuning/examples/prompt-tuning/.gitignore new file mode 100644 index 00000000..d94d6e13 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/prompt-tuning/examples/prompt-tuning/cdn.html b/packages/prompt-tuning/examples/prompt-tuning/cdn.html new file mode 100644 index 00000000..fe966e04 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/cdn.html @@ -0,0 +1,41 @@ + + + + + @carbon-labs/ai-prompt-tuning example + + + + + + + + + + Tag text + + + diff --git a/packages/prompt-tuning/examples/prompt-tuning/index.html b/packages/prompt-tuning/examples/prompt-tuning/index.html new file mode 100644 index 00000000..ee440ed3 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/index.html @@ -0,0 +1,28 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + Tag text + + + diff --git a/packages/prompt-tuning/examples/prompt-tuning/package.json b/packages/prompt-tuning/examples/prompt-tuning/package.json new file mode 100644 index 00000000..f4814ae9 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/package.json @@ -0,0 +1,21 @@ +{ + "name": "carbon-labs-ai-prompt-tuning-example", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "clean": "rimraf node_modules dist .cache", + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "rimraf": "^3.0.2", + "sass": "^1.55.0", + "vite": "^3.2.2" + }, + "dependencies": { + "@carbon/styles": "^1.53.0", + "@carbon-labs/ai-prompt-tuning": "latest" + } +} diff --git a/packages/prompt-tuning/examples/prompt-tuning/src/index.js b/packages/prompt-tuning/examples/prompt-tuning/src/index.js new file mode 100644 index 00000000..33dc8a31 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon-labs/ai-prompt-tuning/es/index.js'; diff --git a/packages/prompt-tuning/examples/prompt-tuning/src/styles.scss b/packages/prompt-tuning/examples/prompt-tuning/src/styles.scss new file mode 100644 index 00000000..29117089 --- /dev/null +++ b/packages/prompt-tuning/examples/prompt-tuning/src/styles.scss @@ -0,0 +1,17 @@ +// +// Copyright IBM Corp. 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/prompt-tuning/index.ts b/packages/prompt-tuning/index.ts new file mode 100644 index 00000000..4f0597a2 --- /dev/null +++ b/packages/prompt-tuning/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './components/prompt-tuning/prompt-tuning.js'; diff --git a/packages/prompt-tuning/package.json b/packages/prompt-tuning/package.json new file mode 100644 index 00000000..20462f7f --- /dev/null +++ b/packages/prompt-tuning/package.json @@ -0,0 +1,41 @@ +{ + "name": "@carbon-labs/ai-prompt-tuning", + "version": "0.0.1", + "publishConfig": { + "access": "public", + "provenance": true + }, + "type": "module", + "description": "Carbon for AI - prompt-tuning component", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/carbon-design-system/carbon-labs", + "directory": "packages/prompt-tuning" + }, + "main": "./src/index.js", + "module": "./src/index.js", + "exports": { + ".": { + "default": "./src/index.js" + }, + "./es/": "./es/" + }, + "files": [ + "es/**/*", + "custom-elements.json" + ], + "types": "./src/index.d.ts", + "customElements": "custom-elements.json", + "scripts": { + "build": "gulp build --option prompt-tuning", + "build:dist": "rm -rf dist && rollup --config ../../tools/rollup.config.dist.js", + "build:dist:canary": "rm -rf dist && rollup --config ../../tools/rollup.config.dist.js --configCanary" + }, + "dependencies": { + "@babel/runtime": "^7.23.2", + "@carbon-labs/utilities": "0.8.0", + "@carbon/grid": "^11.21.0", + "@carbon/web-components": "2.9.0" + } +} diff --git a/yarn.lock b/yarn.lock index bee50c43..89b10a86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2651,6 +2651,17 @@ __metadata: languageName: unknown linkType: soft +"@carbon-labs/ai-prompt-tuning@workspace:packages/prompt-tuning": + version: 0.0.0-use.local + resolution: "@carbon-labs/ai-prompt-tuning@workspace:packages/prompt-tuning" + dependencies: + "@babel/runtime": "npm:^7.23.2" + "@carbon-labs/utilities": "npm:0.8.0" + "@carbon/grid": "npm:^11.21.0" + "@carbon/web-components": "npm:2.9.0" + languageName: unknown + linkType: soft + "@carbon-labs/ai-tag@workspace:packages/tag": version: 0.0.0-use.local resolution: "@carbon-labs/ai-tag@workspace:packages/tag"