diff --git a/.github/workflows/deploy-qa.yml b/.github/workflows/deploy-qa.yml index 1339ad2eb9..2a30e44def 100644 --- a/.github/workflows/deploy-qa.yml +++ b/.github/workflows/deploy-qa.yml @@ -3,7 +3,7 @@ name: Deploy QA on: push: branches: - - master + - v3-ui workflow_dispatch: jobs: diff --git a/packages/backend-core/src/sql/sqlTable.ts b/packages/backend-core/src/sql/sqlTable.ts index f5b02cc4e4..84f4e290aa 100644 --- a/packages/backend-core/src/sql/sqlTable.ts +++ b/packages/backend-core/src/sql/sqlTable.ts @@ -17,7 +17,7 @@ import SchemaBuilder = Knex.SchemaBuilder import CreateTableBuilder = Knex.CreateTableBuilder function isIgnoredType(type: FieldType) { - const ignored = [FieldType.LINK, FieldType.FORMULA] + const ignored = [FieldType.LINK, FieldType.FORMULA, FieldType.AI] return ignored.indexOf(type) !== -1 } @@ -144,6 +144,9 @@ function generateSchema( case FieldType.FORMULA: // This is allowed, but nothing to do on the external datasource break + case FieldType.AI: + // This is allowed, but nothing to do on the external datasource + break case FieldType.ATTACHMENTS: case FieldType.ATTACHMENT_SINGLE: case FieldType.SIGNATURE_SINGLE: diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 2717a1b7d5..31067ab40f 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -2074,6 +2074,7 @@ describe.each([ ) tableId = table._id! + // @ts-ignore - until AI implemented const rowValues: Record = { [FieldType.STRING]: generator.guid(), [FieldType.LONGFORM]: generator.paragraph(), diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 7979fac555..dfd4f50bd1 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -206,7 +206,7 @@ describe.each([ visible: false, icon: "ic", }, - } as Record, + } as ViewV2Schema, } const createdView = await config.api.viewV2.create(newView) @@ -250,7 +250,7 @@ describe.each([ name: "Category", type: FieldType.STRING, }, - } as Record, + } as ViewV2Schema, } await config.api.viewV2.create(newView, { @@ -1044,7 +1044,7 @@ describe.each([ visible: false, icon: "ic", }, - } as Record, + } as ViewV2Schema, }) expect(updatedView).toEqual({ @@ -1078,7 +1078,7 @@ describe.each([ name: "Category", type: FieldType.STRING, }, - } as Record, + } as ViewV2Schema, }, { status: 200, diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index 831528f84d..5f61791683 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -56,6 +56,7 @@ interface AuthTokenResponse { const isTypeAllowed: Record = { [FieldType.STRING]: true, [FieldType.FORMULA]: true, + [FieldType.AI]: true, [FieldType.NUMBER]: true, [FieldType.LONGFORM]: true, [FieldType.DATETIME]: true, @@ -490,7 +491,8 @@ export class GoogleSheetsIntegration implements DatasourcePlus { } if ( !sheet.headerValues.includes(key) && - column.type !== FieldType.FORMULA + column.type !== FieldType.FORMULA && + column.type !== FieldType.AI ) { updatedHeaderValues.push(key) } diff --git a/packages/server/src/integrations/utils/utils.ts b/packages/server/src/integrations/utils/utils.ts index 43302de36f..73b2f637f8 100644 --- a/packages/server/src/integrations/utils/utils.ts +++ b/packages/server/src/integrations/utils/utils.ts @@ -242,6 +242,7 @@ function copyExistingPropsOver( let shouldKeepSchema = false switch (existingColumnType) { case FieldType.FORMULA: + case FieldType.AI: case FieldType.AUTO: case FieldType.INTERNAL: shouldKeepSchema = true diff --git a/packages/server/src/sdk/app/tables/internal/sqs.ts b/packages/server/src/sdk/app/tables/internal/sqs.ts index bd71644537..7533e2b22a 100644 --- a/packages/server/src/sdk/app/tables/internal/sqs.ts +++ b/packages/server/src/sdk/app/tables/internal/sqs.ts @@ -19,6 +19,7 @@ const FieldTypeMap: Record = { [FieldType.BOOLEAN]: SQLiteType.NUMERIC, [FieldType.DATETIME]: SQLiteType.TEXT, [FieldType.FORMULA]: SQLiteType.TEXT, + [FieldType.AI]: SQLiteType.TEXT, [FieldType.LONGFORM]: SQLiteType.TEXT, [FieldType.NUMBER]: SQLiteType.REAL, [FieldType.STRING]: SQLiteType.TEXT, diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index cf6d47053a..ad2ec5bec3 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -605,6 +605,7 @@ export function fullSchemaWithoutLinks({ }): { [type in Exclude]: FieldSchema & { type: type } } { + // @ts-ignore - until AI implemented return { [FieldType.STRING]: { name: "string", diff --git a/packages/shared-core/src/table.ts b/packages/shared-core/src/table.ts index e81e8266cc..73e3ad6cb7 100644 --- a/packages/shared-core/src/table.ts +++ b/packages/shared-core/src/table.ts @@ -8,6 +8,7 @@ const allowDisplayColumnByType: Record = { [FieldType.NUMBER]: true, [FieldType.DATETIME]: true, [FieldType.FORMULA]: true, + [FieldType.AI]: true, [FieldType.AUTO]: true, [FieldType.INTERNAL]: true, [FieldType.BARCODEQR]: true, @@ -38,6 +39,7 @@ const allowSortColumnByType: Record = { [FieldType.JSON]: true, [FieldType.FORMULA]: false, + [FieldType.AI]: false, [FieldType.ATTACHMENTS]: false, [FieldType.ATTACHMENT_SINGLE]: false, [FieldType.SIGNATURE_SINGLE]: false, @@ -62,6 +64,7 @@ const allowDefaultColumnByType: Record = { [FieldType.BIGINT]: false, [FieldType.BOOLEAN]: false, [FieldType.FORMULA]: false, + [FieldType.AI]: false, [FieldType.ATTACHMENTS]: false, [FieldType.ATTACHMENT_SINGLE]: false, [FieldType.SIGNATURE_SINGLE]: false, diff --git a/packages/types/src/documents/app/row.ts b/packages/types/src/documents/app/row.ts index 673d481e3c..b0c5267b37 100644 --- a/packages/types/src/documents/app/row.ts +++ b/packages/types/src/documents/app/row.ts @@ -76,6 +76,13 @@ export enum FieldType { * that is part of the initial formula definition, the formula will be live evaluated in the browser. */ AUTO = "auto", + /** + * A complex type, called an AI column within Budibase. This type is only supported against internal tables + * and calculates the output based on a chosen operation (summarise text, translation etc) which passes to + * the configured Budibase Large Language Model to retrieve the output and write it back into the row. + * AI fields function in a similar fashion to static formulas, and possess many of the same characteristics. + */ + AI = "ai", /** * a JSON type, called JSON within Budibase. This type allows any arbitrary JSON to be input to this column * type, which will be represented as a JSON object in the row. This type depends on a schema being diff --git a/packages/types/src/documents/app/table/constants.ts b/packages/types/src/documents/app/table/constants.ts index fffaddc5df..117cfa0eba 100644 --- a/packages/types/src/documents/app/table/constants.ts +++ b/packages/types/src/documents/app/table/constants.ts @@ -30,6 +30,7 @@ export enum JsonFieldSubType { export enum FormulaType { STATIC = "static", DYNAMIC = "dynamic", + AI = "ai", } export enum BBReferenceFieldSubType { diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index b98a0a3d4a..45d0aa78d2 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -9,6 +9,7 @@ import { JsonFieldSubType, RelationshipType, } from "./constants" +import { AIOperationEnum } from "../../../sdk/ai" export interface UIFieldMetadata { order?: number @@ -116,6 +117,16 @@ export interface FormulaFieldMetadata extends BaseFieldSchema { formulaType?: FormulaType } +export interface AIFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum + columns?: string[] + column?: string + categories?: string[] + prompt?: string + language?: string +} + export interface BBReferenceFieldMetadata extends Omit { type: FieldType.BB_REFERENCE @@ -194,6 +205,7 @@ interface OtherFieldMetadata extends BaseFieldSchema { | FieldType.LINK | FieldType.AUTO | FieldType.FORMULA + | FieldType.AI | FieldType.NUMBER | FieldType.LONGFORM | FieldType.BB_REFERENCE @@ -211,6 +223,7 @@ export type FieldSchema = | RelationshipFieldMetadata | AutoColumnFieldMetadata | FormulaFieldMetadata + | AIFieldMetadata | NumberFieldMetadata | LongFormFieldMetadata | StringFieldMetadata diff --git a/packages/types/src/sdk/ai.ts b/packages/types/src/sdk/ai.ts new file mode 100644 index 0000000000..345effa939 --- /dev/null +++ b/packages/types/src/sdk/ai.ts @@ -0,0 +1,91 @@ +export enum AIOperationEnum { + SUMMARISE_TEXT = "SUMMARISE_TEXT", + CLEAN_DATA = "CLEAN_DATA", + TRANSLATE = "TRANSLATE", + CATEGORISE_TEXT = "CATEGORISE_TEXT", + SENTIMENT_ANALYSIS = "SENTIMENT_ANALYSIS", + PROMPT = "PROMPT", + SEARCH_WEB = "SEARCH_WEB", +} + +export enum OperationFieldTypeEnum { + MULTI_COLUMN = "columns", + COLUMN = "column", + BINDABLE_TEXT = "prompt", +} + +export type OperationFieldsType = { + [AIOperationEnum.SUMMARISE_TEXT]: { + columns: OperationFieldTypeEnum.MULTI_COLUMN + } + [AIOperationEnum.CLEAN_DATA]: { + column: OperationFieldTypeEnum.COLUMN + } + [AIOperationEnum.TRANSLATE]: { + column: OperationFieldTypeEnum.COLUMN + language: OperationFieldTypeEnum.BINDABLE_TEXT + } + [AIOperationEnum.CATEGORISE_TEXT]: { + columns: OperationFieldTypeEnum.MULTI_COLUMN + categories: OperationFieldTypeEnum.BINDABLE_TEXT + } + [AIOperationEnum.SENTIMENT_ANALYSIS]: { + column: OperationFieldTypeEnum.COLUMN + } + [AIOperationEnum.PROMPT]: { + prompt: OperationFieldTypeEnum.BINDABLE_TEXT + } + [AIOperationEnum.SEARCH_WEB]: { + columns: OperationFieldTypeEnum.MULTI_COLUMN + } +} + +type BaseSchema = { + operation: AIOperationEnum +} + +type SummariseTextSchema = BaseSchema & { + operation: AIOperationEnum.SUMMARISE_TEXT + columns: string[] +} + +type CleanDataSchema = BaseSchema & { + operation: AIOperationEnum.CLEAN_DATA + column: string +} + +type TranslateSchema = BaseSchema & { + operation: AIOperationEnum.TRANSLATE + column: string + language: string +} + +type CategoriseTextSchema = BaseSchema & { + operation: AIOperationEnum.CATEGORISE_TEXT + columns: string[] + categories: string[] +} + +type SentimentAnalysisSchema = BaseSchema & { + operation: AIOperationEnum.SENTIMENT_ANALYSIS + column: string +} + +type PromptSchema = BaseSchema & { + operation: AIOperationEnum.PROMPT + prompt: string +} + +type SearchWebSchema = BaseSchema & { + operation: AIOperationEnum.SEARCH_WEB + columns: string[] +} + +export type AIColumnSchema = + | SummariseTextSchema + | CleanDataSchema + | TranslateSchema + | CategoriseTextSchema + | SentimentAnalysisSchema + | PromptSchema + | SearchWebSchema diff --git a/packages/types/src/sdk/index.ts b/packages/types/src/sdk/index.ts index d87ec58b0c..86eb5b1a24 100644 --- a/packages/types/src/sdk/index.ts +++ b/packages/types/src/sdk/index.ts @@ -1,3 +1,4 @@ +export * from "./ai" export * from "./automations" export * from "./hosting" export * from "./context"